问题 Threadpool实现:condition_variables vs. yield()


我尝试在C ++中开发一个线程池,我想知道在工作线程的主循环中是否更好地yield()线程或者在条件变量上等待:

void worker_thread( void )
{
    // this is more or less pseudocode
    while( !done )
    {

        if( task_available ) 
             run_task();
        else
            std::this_thread::yield();
    }
}

void worker_thread( void )
{
    // this is more or less pseudocode

    std::unique_lock< std::mutex > lk( mutex_ );
    while( !done )
    {

        if( task_available ) 
             run_task();
        else
            condition_.wait( lk );
    }
}

有任何想法吗?两个版本之间是否会有任何性能差异?


12456
2017-07-12 11:16


起源



答案:


如果线程池中的线程不断地提供任务并且你需要快速的响应时间,那么yield就是你想要的,但是无论等待线程在做什么,yield都会烧掉cpu周期。 如果没有,你可以使用条件方法,线程将睡眠直到任务准备就绪(注意,条件可以唤醒一个线程,即使没有发送就绪信号),响应时间可能会更慢,但你不会烧cpu周期。

我会推荐条件方法,如果反应时间太慢,请切换到收益率。


8
2017-07-12 11:29



条件方法是如何实施的?他们是否有类似于上面的worker_thread的等待机制? - headmyshoulder
yield会导致调用线程执行另一个准备在当前处理器上运行的线程(请参阅SwitchToThread for windows)。 - Tiemo Jung
有关条件,请参阅pthread_cond_wait。所以它导致线程进入睡眠状态,直到条件被触发(就像在Windows上的事件) - Tiemo Jung
那么检查条件变量是否放入“主调度程序”? - headmyshoulder
轮询解决方案通常没有希望,浪费CPU周期和内存带宽。 - Martin James


答案:


如果线程池中的线程不断地提供任务并且你需要快速的响应时间,那么yield就是你想要的,但是无论等待线程在做什么,yield都会烧掉cpu周期。 如果没有,你可以使用条件方法,线程将睡眠直到任务准备就绪(注意,条件可以唤醒一个线程,即使没有发送就绪信号),响应时间可能会更慢,但你不会烧cpu周期。

我会推荐条件方法,如果反应时间太慢,请切换到收益率。


8
2017-07-12 11:29



条件方法是如何实施的?他们是否有类似于上面的worker_thread的等待机制? - headmyshoulder
yield会导致调用线程执行另一个准备在当前处理器上运行的线程(请参阅SwitchToThread for windows)。 - Tiemo Jung
有关条件,请参阅pthread_cond_wait。所以它导致线程进入睡眠状态,直到条件被触发(就像在Windows上的事件) - Tiemo Jung
那么检查条件变量是否放入“主调度程序”? - headmyshoulder
轮询解决方案通常没有希望,浪费CPU周期和内存带宽。 - Martin James


无论哪种方式,线程切换的成本都是相同的。至于你是否应该使用轮询或条件变量,后者可以通过踢掉线程来休息处理器,直到确实有事情要做。这导致CPU利用率降低。轮询方法将允许线程返回并“再次尝试”,有效地无限运行CPU。

值得指出的是,有一些应用程序喜欢轮询,比如何时 task_available 在很短的时间内是假的(即通常有工作要做)。在这种情况下,您将要进行轮询 task_available 在一个带计数器的循环中;仅在计数器超过阈值时才产生线程。


5
2017-07-12 11:30