2016-10-31 22 views
0

私はゼロレイテンシのクラウドゲームサーバーを作成しています。それはソフトウェアのパイプラインです。最初の段階では画面をキャプチャし、2番目の段階ではビデオにエンコードします。スレッドスターベートを防ぐ方法

しかし第二段階のフリーズ、ある程度の時間後。私は多くのプラットフォームに依存しないアプローチを試みましたが、静脈ではどちらかが最終的にフリーズします。 How to prevent threads from starvation in C++11の答えは、mutexを使うべきだと述べています。私はそれを試してみました。それは長く続くことができますが、時には(まれに)時折凍ることがあります。ミューテックスはスレッドの飢餓を防ぐための明確なヒントではないと私は思う。 (多分私が間違っているの?)

今私はミューテックスを使用すると同時に、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

私は、スレッドが何をしているのスタックトレースを取ることをお勧めします。スレッドがWaitForSingleObjectのような関数に座っていると、大きな糸口ができます。一列に2つのスタックトレースを入れて確かめてください。 – Steve

+0

私はbrofiler(githubで利用可能)と呼ばれるプロファイラを使用します。 Windows APiIをフックします。私はWaitForSingleObjectを明示的に呼び出さなかった。しかし、それはスレッドがそれに入るようです。 (しかし、それは戻ってくるでしょう) –

+3

うーん、もし本当に*飢えの問題だったら、ブースト機能を削除するのは間違ったことです。あなたはデッドロックの問題を隠している、非常に悪い考え。プロデューサー - コンシューマーロックは、Boostとwinapi(InitializeSRWLockなど)からすぐに入手できます。自分で作成しないでください。 –

答えて

2

ワード凍結は、スレッドの不足ではなく、競合状態を意味します....ミューテックス何も変更を追加してみてください。関係するすべてのスレッドが単一のミューテックスおよび単一のスレッド(またはスレッドの数)飢餓状態に他のスレッドを残しミューテックスをつかんで保持するために競合している場合

スレッド不足です。これは、1つのミューテックスに対する競争がそれほどない場合には、悪いアプリケーション設計の例です。

しかし、あなたはフリーズしています。だから凍結とは、(2つ以上の)スレッドのどちらもミューテックスやコード内の他の制約を取得できないレース状態になったことを意味します。

いかなる価値のある答えを提供するために、あなたの質問に十分な情報がありません。正確に何をしているのか正確に何が起こっているのかのコードサンプルを提供してください。

+0

私はできるだけ早く私のコードを提供します –

+0

私は競合状態が発生するとは思わない。プロデューサとコンシューマが1つしかないので(ただし、もう一度チェックします)、プログラムを一時停止して、各スレッドの実行場所を確認します。 "freezed"スレッドはランダムな線で停止します。 –

+0

こんにちはTim。あなたのコードを凍結する可能性の数は膨大です。循環キュー(ストリーマー)との競合状態になる可能性があります。画面キャプチャのルーティングに関するリソースの問題により、アプリが不安定になっている可能性があります。キャプチャバッファがメモリをリークしている可能性があります。つまり、循環キューが実際には循環していない可能性があります。申し訳ありませんが、あまりにも多くの可能性があります。 – tcwicks

0

私は私のローカル変数は私の同僚の機能によって破損していることがわかりました。 libx264が正しく動作しない。実際には、コードはロックフリーで書くことができます。 stiil、ミューテックスを追加することはビジーな待合よりも優れています。 CPU使用量を大幅に減らすことができます

+1

私はあなたがパラレルプログラミングの専門家であるという印象はありません。複数のスレッドが同じデータに同時にアクセスする場合は、自分自身でロックを使用してください。 –

+0

ありがとうございます。私は後で循環キューにロックを追加しました。 –

関連する問題