C++:条件变量等待
C++: condition-variable wait
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
std::mutex globalMutex;
std::condition_variable globalCondition;
int global = 0;
int activity = 0;
int CountOfThread = 1; // or more than 1
// just for console display, not effect the problem
std::mutex consoleMutex;
void producer() {
while (true) {
{
std::unique_lock<std::mutex> lock(globalMutex);
while (activity == 0) {
lock.unlock();
std::this_thread::yield();
lock.lock();
}
global++;
globalCondition.notify_one();
}
std::this_thread::yield();
}
}
void customer() {
while (true) {
int x;
{
std::unique_lock<std::mutex> lock(globalMutex);
activity++;
globalCondition.wait(lock); // <- problem
activity--;
x = global;
}
{
std::lock_guard<std::mutex> lock(consoleMutex);
std::cout << x << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int _tmain(int argc, _TCHAR* argv[])
{
for (int i = 0; i < CountOfThread; ++i) {
std::thread(customer).detach();
}
std::thread(producer).detach();
getchar();
return 0;
}
我想要的是确保每次有客户线程获得增加的全局时,期望显示如下:1、2、3、...,但我看到的是全局值将在等待和活动之间增加--,因此,实际显示是:1、23、56、78、....
我发现问题出在wait((,在wait((中有3个步骤,"解锁,等待,锁定",在signaled(wait return(和mutex.lock之间,这不是原子操作,生产者线程可能会在wait((之前锁定互斥锁以锁定互斥锁,并且活动仍然不为零,因此全局将意外增加
有没有办法确定我的期望?
您的问题是,当activity
> 0 时,producer
可以循环抓取锁、递增全局并通知条件变量。 (通知不必有相应的服务员(。
您反复致电thread.yield
有点危险信号 - 它们意味着您正在投票,而不是等待。 我认为解决方案是您需要两个条件变量。 生产者等待一个,直到被消费者通知,消费者等待另一个,直到生产者通知它。 不过,我不太确定您如何与多个消费者一起做到这一点。
我发现它可以帮助我在线程的上下文中做事。例如,如果您是客户,您还在等什么?你的意思是,在线程的上下文中。当您这样思考时,使用监视器进行编码变得非常简单。
现在,正如马丁所说,我相信反复打电话给thread.yield
有点可怕。这可能会导致可怕的代码交错。
为了展示代码不起作用的原因的示例,让我们快速交错:
- 创建了几个客户,抓住锁的客户增加了
activity
。然后该线程由于调用wait
而进入睡眠状态。 - 另一个线程在初始客户线程调用
wait
后唤醒。这是因为wait
解锁了传递到其中的互斥锁。 - 该线程获取
globalMutex
并增加activity
。然后它等待。 - 对
CountOfThread
线程数重复此操作,因为这在多线程代码中是完全可能的。 - 最后,生产者线程运行,查看
activity == 0
,并解锁。但是,它没有notify_one
(即信号(。然后它屈服了。这可能会导致代码未定义且令人困惑。
我的建议:
- 切勿在等待条件时打电话
yield
。这可能会导致复杂且难以阅读的无效监视器代码。 - 考虑每个线程正在等待的条件。如果不同的代码段正在等待不同的条件,请创建不同的锁。对于一段共享代码,只能使用一个锁。
- 在某些情况下,对不同的条件使用不同的条件变量。如果条件依赖于不同的数据,请务必使用不同的条件变量。
在您的情况下,解决方案并不像您想象的那么复杂。使用我最初的建议:在线程的上下文中思考。例如,当生产者线程正在运行时,当客户没有注意到global
已更改时,它希望等待。当客户线程正在运行时,它希望等待生产者未更改global
。
下面是您想要的行为的示例:
mutex m;
condition_variable cv;
int global = 0, prev_global = 0;
void producer()
{
while (true)
{
unique_lock<mutex> lock(m);
while (prev_global != global)
{
cv.wait(lock);
}
prev_global = global++;
cv.notify_one();
lock.unlock();
}
}
void customer()
{
while (true)
{
unique_lock<mutex> lock(m);
while (prev_global == global)
{
cv.wait(lock);
}
prev_global = global;
cv.notify_one();
lock.unlock();
}
}
int main()
{
vector<thread> pool;
for (int i = 0; i < 5; ++i)
{
pool.push_back(thread (customer));
}
pool.push_back(thread (producer));
for (auto it = pool.begin(); it != pool.end(); ++it)
{
it->join();
}
return 0;
}
- 子线程中的条件变量等待停止主线程中的执行
- 正在连接的等待条件变量的线程会发生什么情况?
- 如何"stop"正在等待条件变量的分离线程?
- 如何修复条件变量等待/通知的竞争条件
- 可以在同一条件变量上等待多个线程
- 一个线程如何制作东西而不是在条件变量上等待
- 等待条件变量后未并行运行的线程
- "cin >>变量"不等待输入
- 我将如何连续更新变量,并同时等待输入
- 等待条件变量是否会加载 CPU 内核
- 你真的能用WaitFor..等待条件变量吗..对象
- 等待中有条件变量的班级破坏
- 条件变量 - 等待/通知种族条件
- C++条件变量并等待
- 中断已处于条件变量等待调用中的提升线程
- 在发出等待条件变量的信号后,线程何时获取锁?是什么决定了它
- 等待从获取锁的函数调用的帮助程序函数中的条件变量
- 线程同步:等待两个bool变量
- 使用易失性布尔变量忙于等待
- 难以理解条件变量等待