0

我正在编写一个零延迟的云游戏服务器。这是一个软件管道。在第一阶段,我们捕获屏幕,在第二阶段,我们将其编码为视频。

然而,经过一段时间后,第二阶段冻结。我尝试了许多独立于平台的方法,但是它们中的任何一个最终都会冻结。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);
        }

    }
...

最初我没有对循环队列做任何保护。我认为没有竞争条件(一个生产者和一个消费者)。然后我尝试添加互斥体但没有任何改变......

4

2 回答 2

2

冻结一词意味着竞争条件而不是线程饥饿。

线程饥饿是指所有相关线程都在竞争一个互斥锁,并且一个线程(或几个线程)不断获取互斥锁,而其他线程则处于饥饿状态。如果您对单个 Mutex 有如此多的竞争,那么这是一个糟糕的应用程序设计示例。

但是你说冻结。因此,冻结意味着您最终处于竞争状态,其中(两个或更多)线程都无法获得代码中的互斥锁或其他约束。

您的问题中没有足够的信息来提供任何有价值的答案。请提供一个代码示例,说明您正在做什么以及正在发生什么。

于 2016-10-31T04:47:57.217 回答
0

我发现我的局部变量被我同事的函数破坏了。使 libx264 无法正常工作。实际上代码可以写成无锁的。不过,添加互斥锁总比忙着等待要好。可以大大降低cpu使用率

于 2016-10-31T08:48:37.377 回答