如何防止线程饥饿

时间:2016-10-31 04:35:56

标签: c++ multithreading c++11 starvation

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

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

    }
...

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

2 个答案:

答案 0 :(得分:2)

冷冻这个词意味着竞争条件而不是线索饥饿。

线程饥饿是所有相关线程都在竞争单个互斥锁的地方,而单个线程(或一些线程)继续抓住互斥锁而其他线程被饿死。如果您对单个Mutex有太多的竞争,那么这就是一个糟糕的应用程序设计的例子。

然而你说冻结。因此,冻结意味着您已经达到了Race条件,其中(两个或更多)线程都不能获取代码中的互斥锁或其他约束。

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

答案 1 :(得分:0)

我发现我的同事的功能损坏了我的局部变量。使libx264工作不正常。实际上代码可以无锁写。 stiil,添加互斥量比忙碌等待更好。可以大大降低CPU使用率