std::condition_variable和std::condition_variable_any之间有什么区别

What is the difference between std::condition_variable and std::condition_variable_any?

本文关键字:std condition variable 什么 区别 any 之间      更新时间:2023-10-16

我可能遗漏了一些明显的东西,但我看不出std::condition_variablestd::condition_variable_any之间有任何区别。为什么我们两者都需要?

区别在于wait()函数的参数。std::condition_variable中的所有等待函数都采用std::unique_lock<std::mutex>&类型的锁定参数,而std::condition_variable_any的等待函数都是模板,并且采用Lockable&类型的锁参数,其中Lockable是模板参数。

这意味着std::condition_variable_any可以处理用户定义的互斥锁和锁类型,也可以处理像boost::shared_lock这样的东西——任何具有lock()unlock()成员函数的东西。

例如

std::condition_variable_any cond;
boost::shared_mutex m;
void foo() {
    boost::shared_lock<boost::shared_mutex> lk(m);
    while(!some_condition()) {
        cond.wait(lk);
    }
}

从C++20开始,condition_variable_any还支持新的jthread类的停止标记。这意味着,如果您有这种类型的条件变量,那么在发出停止请求时,它将放弃互斥锁,而无需编写额外的轮询代码。由于一些技术原因,这个特性在condition_variable上不起作用,这些原因导致了"争用、死锁和未定义的行为"

void testInterruptibleCVWait()
{
    bool ready = false;
    std::mutex readyMutex;
    std::condition_variable_any readyCV;
    std::jthread t([&ready, &readyMutex, &readyCV] (std::stop_token st)
    {
        while (...)
        {
            ...
            {
                std::unique_lock lg{readyMutex};
                readyCV.wait_until(lg, [&ready] {return ready; }, st);
                // also ends wait on stop request for st
            }
            ...
        }
   });
...
} // jthread destructor signals stop request and therefore unblocks the CV wait and ends the started thread

有关详细信息,请参阅文档:

std::condition_variable文档

std::condition_variable_any文档,并具体查看waitwait_forwait_until成员函数,这些函数现在在jthreads上接受停止请求。

或者查看最新的jthread和停止令牌C++20提案修订版

std::condition_variable更专业,因此在不需要std::condition_variable_any的灵活性时可以更高效。

根据N3290§30.5【线程条件】/1

condition_variable类提供只能等待类型为unique_lock<mutex>的对象的条件变量,允许一些平台上的效率。类condition_variable_any提供了一个通用条件变量可以等待用户提供的锁类型的对象。

实际上,在LLVM的libc++中,condition_variable_any是使用shared_mutex上更专业的condition_variable(使用pthread_cond_t)实现的。