Reputation: 412
I am writing a zero-latency cloud gaming server. It's a software pipeline. In the first stage we capture the screen and in the second stage we encode it to the video.
However after some amount of time the second stage freezes. I tried many platform-indepandent approach, but in vein, either of them will freeze eventually. The answer of How to prevent threads from starvation in C++11 stated that we should use mutex. I tried it. And it can last longer but it still freeze sometimes(rarely). I think mutex is not a explicit hint to prevent thread starvation too. (maybe I am doing wrong?)
Now I use mutex and disable Windows priority boost feature at the same time, but I don't like this solution at all. could anyone provide an example of starvation-free producer and consumer(better in C++11)?
producer:
while(Streamer.IsConnected()) {
uint8_t *pBits = Streamer.AcquireNext();
// The buffer is full
if(pBits && get_counter(&fps_limiter) >= 1000 / args.m_MaxFps && check_target_window(args.m_TargetWindow.c_str(), limit, &rect)) {
BROFILER_FRAME("MainLoop")
start_counter(&fps_limiter);
if(!FAILED(capture_screen(g_DXGIManager, rect, pBits)))
Streamer.PushNext();
}
else {
this_thread::yield();
// lower cpu usage
Sleep(1);
continue;
}
if (get_counter(&bit_rate) >= 1000) {
uint32_t bps = Streamer.GetBitRate();
printf("\rBirate: %u bps, %u Bps\t\t\t\t\t", bps, bps/8);
start_counter(&bit_rate);
}
}
consumer:
while(!m_ServerShouldStop) {
uint8_t *data = AcquireLast();
if (!data) {
this_thread::yield();
Sleep(1);
continue;
}
// encoder callback
uint8_t *out;
uint32_t size = m_Encoder(data, &out);
PopLast();
// If encoder output something, send it immediately
if(size>0) {
// send the size of buffer
int res1 = ::send_whole_buffer(client_sck, reinterpret_cast<uint8_t *>(&size),
sizeof(size));
// then the contents
int res2 = ::send_whole_buffer(client_sck, out, size);
bytes += size;
if (m_EventHandler)
m_EventHandler->onFrameSent();
// If any of them fails....
if(!res1||!res2)
break;
}
if (get_counter(&counter) >= 1000) {
m_Bps = bytes * 8;
bytes = 0;
start_counter(&counter);
}
}
...
Initially I did not do any protection to circular queue. I think there no race condition(one producer and one consumer). Then I try to add mutex but nothing change....
Upvotes: 0
Views: 3338
Reputation: 412
I found that my local variable is corrupted by my colleague's function. Making libx264 work incorrectly. Actually the code can be written lock-free. stiil, adding mutex is better than busy waiting. can lower the cpu usage a lot
Upvotes: 0
Reputation: 505
The word Freezing implies a race condition rather than thread starvation.
Thread starvation is where all threads concerned are competing for a single mutex and a single thread (or a few of the threads) keep grabbing the mutex leaving the other threads starved. This is an example of a bad application design if you have that much competition for a single Mutex.
However you said Freezing. So freezing implies you have ended up in a Race condition where neither of (two or more) threads can get the mutex or some other constraint in your code.
There isn't enough information in your question to provide any worthwhile answer. Please provide a code sample of exactly what you are doing and exactly what is happening.
Upvotes: 2