C++ 条件变量的常见用例场景
条件变量可用于向其他线程发出发生了某些事情的信号:C++ 条件变量的常见用例场景,c++,multithreading,synchronization,c++11,C++,Multithreading,Synchronization,C++11,条件变量可用于向其他线程发出发生了某些事情的信号: mutex m; condition_variable cv; thread t1([&cv]{ // processing ... cv.notify_one(); }); ... unique_lock<std::mutex> lck(m); cv.wait(lck); mutexm; 条件变量cv; 螺纹t1([&cv]{ //加工 ... cv.通知_one(); }); ... 唯一锁定
mutex m;
condition_variable cv;
thread t1([&cv]{
// processing
...
cv.notify_one();
});
...
unique_lock<std::mutex> lck(m);
cv.wait(lck);
mutexm;
条件变量cv;
螺纹t1([&cv]{
//加工
...
cv.通知_one();
});
...
唯一锁定lck(m);
cv.等待(lck);
但是正如您所看到的,在我们等待被通知之前,有一个机会窗口,线程处理已经完成,通知正在通过,所以我们将永远等待
在这种情况下,常见的解决方案是使用标志:
mutex m;
condition_variable cv;
bool done = false;
thread t1([&cv,&done]{
// processing
...
done = true;
cv.notify_one();
});
...
unique_lock<std::mutex> lck(m);
cv.wait(lck, [&done]{return done;});
mutexm;
条件变量cv;
bool done=false;
线程t1([&cv,&done]{
//加工
...
完成=正确;
cv.通知_one();
});
...
唯一锁定lck(m);
cv.wait(lck,[&done]{return done;});
使用标志是使用
条件变量的常见方式吗?还是我的解释有误?通常在一个线程检测到它无法继续并决定等待某个条件(在英语意义上)得到满足的情况下使用条件变量。condition\u变量
本身并不是通知线程应该继续的主要机制,而是通知如果有线程正在等待,它应该重新检查,因为状态可能已经更改,现在可以继续了
最简单的示例之一是生产者/消费者队列,其中消费者将有如下代码:
void consume() {
empty.wait( [&] { return !queue.empty(); } );
// extract data from the queue and consume it here
}
也就是说,线程不仅仅在等待条件_变量
变量,而是在等待对象的状态使线程能够继续。类似地,通知条件_变量
并不是告诉另一个线程继续,只是通知任何等待条件满足的线程重新测试,因为状态可能已更改
回到您的用例,如果您的线程继续需要满足的条件是另一个线程已完成,那么使用这样的标志是完全正确的。条件变量应始终与某个条件相关联,您应该测试:
unique_lock<mutex> lck(m);
while (!something)
cv.wait(lck);
(在简单的情况下,我发现显式而循环更容易阅读。)
正在使用的条件变量可以看作是由条件变量、互斥体和谓词组成的3元组,它们通过一起使用来等待条件变量而在概念上绑定在一起。特定条件变量对象上的所有并发等待必须使用相同的互斥量,并且通常也将在相同的谓词(或依赖于相同数据、受相同互斥量保护的相关谓词)上等待。acondition\u variable
不是信号量,用例是/可以是不同的,用法也不同。您可以使用互斥体和条件变量模拟信号量,这就是您使用done
标志所做的:模拟二进制信号量,我把它看作是一个信号量。有没有任何例子,我会使用一个没有标志或某种条件的条件变量?@IonTodirel,我想不出来。在我遇到的所有用例中,都有一些基本条件决定了等待的必要性;如果你没有“某种类型的标志或条件”,那么你就缺少了使用condvar所需的三分之一的成分(至少是为了正确和安全地使用它)。有趣的是,我很好奇为什么wait
,在condition\u variable
上,有一个不带谓词的重载,这可能是为了灵活性和放松在C++11之前实现条件变量的设计库通常只有重载,但事实是使用这些库的代码(boost::thread更接近)最终看起来都是一样的:while(condition)condition\u variable.wait()
,这就是为什么他们添加了带函子的重载。注意,在lambdas之前,编写函子并不是那么容易。对于lambdas,新的重载是有意义的,但对于一些简单的情况,它可能没有意义,而一个简单的while(!done)cond.wait()
可能比编写lambda更简单。请注意,您的示例相当于wait
Yes的谓词版本,但正如我编辑它所显示的,读取谓词重载并不总是更容易
unique_lock<mutex> lck(m);
cv.wait(lck, [&] { return something; });