0

待ち時間ゼロのクラウド ゲーム サーバーを作成しています。これはソフトウェア パイプラインです。最初の段階で画面をキャプチャし、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 つのコンシューマー) はないと思います。次に、ミューテックスを追加しようとしましたが、何も変わりません....

4

2 に答える 2

2

フリーズという言葉は、スレッドの枯渇ではなく競合状態を意味します。

スレッド スターベーションとは、関連するすべてのスレッドが 1 つのミューテックスを求めて競合し、1 つのスレッド (またはいくつかのスレッド) がミューテックスを取得し続け、他のスレッドを飢えさせたままにすることです。これは、1 つの Mutex をめぐって多くの競合が発生している場合、不適切なアプリケーション設計の例です。

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

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

于 2016-10-31T04:47:57.217 に答える