待ち時間ゼロのクラウド ゲーム サーバーを作成しています。これはソフトウェア パイプラインです。最初の段階で画面をキャプチャし、2 番目の段階でそれをビデオにエンコードします。
ただし、しばらくすると、2 番目のステージがフリーズします。プラットフォームに依存しない多くのアプローチを試しましたが、どちらも最終的にフリーズします。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);
}
}
...
最初は、循環キューに対する保護は何もしませんでした。競合状態 (1 つのプロデューサーと 1 つのコンシューマー) はないと思います。次に、ミューテックスを追加しようとしましたが、何も変わりません....