【发布时间】:2016-10-31 04:35:55
【问题描述】:
我正在编写一个零延迟的云游戏服务器。这是一个软件管道。在第一阶段,我们捕获屏幕,在第二阶段,我们将其编码为视频。
但是,经过一段时间后,第二阶段会冻结。我尝试了许多独立于平台的方法,但是它们中的任何一个最终都会冻结。 How to prevent threads from starvation in C++11 的回答说我们应该使用互斥锁。我尝试过这个。它可以持续更长时间,但有时仍会冻结(很少)。我认为互斥锁也不是防止线程饥饿的明确提示。 (也许我做错了?)
现在我同时使用互斥锁和禁用 Windows 优先级提升功能,但我根本不喜欢这个解决方案。谁能提供一个无饥饿的生产者和消费者的例子(在 C++11 中更好)?
制作人:
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);
}
}
消费者:
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);
}
}
...
最初我没有对循环队列做任何保护。我认为没有竞争条件(一个生产者和一个消费者)。然后我尝试添加互斥体,但没有任何改变......
【问题讨论】:
-
我建议对线程正在执行的操作进行堆栈跟踪。如果一个线程位于像 WaitForSingleObject 这样的函数中,它应该会给你一个很大的线索。确保连续执行几个堆栈跟踪。
-
我使用了一个名为 brofiler 的分析器(在 github 上可用)。它将挂钩 Windows APII。我没有明确调用 WaitForSingleObject。但似乎线程会进入它。 (但它会返回)
-
嗯,不,如果它真的是一个饥饿问题,那么删除提升功能就是错误的做法。你隐藏了一个死锁问题,非常糟糕的主意。生产者-消费者锁很容易从 Boost 和 winapi(InitializeSRWLock 等)中获得,不要自己编写。
-
在 C++11 锁中可用吗?
-
我提供上面的代码,如果有什么遗漏请告诉我
标签: c++ multithreading c++11 starvation