[英]std::condition_variable::wait in c++
我对互斥锁、锁定和等待有点困惑。
这是我的代码:
void producer(std::mutex* m, std::condition_variable* cv,bool* signal) {
std::this_thread::sleep_for(std::chrono::seconds(1));
m->lock();
*signal = true;
m->unlock();
std::this_thread::sleep_for(std::chrono::seconds(3));
cv->notify_one();
printf("notify one\n");
std::this_thread::sleep_for(std::chrono::seconds(10000));
}
void consumer(std::mutex*m, std::condition_variable* cv, bool* signal, int index) {
if(index == 2) std::this_thread::sleep_for(std::chrono::seconds(2));
std::unique_lock<std::mutex> lk(*m);
cv->wait(lk, [&] { return (*signal); });
printf("consumer %d passes this point!\n", index);
std::this_thread::sleep_for(std::chrono::seconds(10000));
}
int main() {
bool signal = false;
std::mutex m;
std::condition_variable cv;
std::thread th1(producer, &m, &cv, &signal);
std::thread th2(consumer, &m, &cv, &signal, 1);
std::thread th3(consumer, &m, &cv, &signal, 2);
th1.join();
th2.join();
th3.join();
return 0;
}
添加了std::this_thread::sleep_for
来解释我的问题。 有生产者、消费者1和消费者2。我认为这段代码应该如下工作:
std::unique_lock<std::mutex> lk(*m);
所以它锁定。cv->wait
。 因为signal
的初始值为false
,所以 consumer1 被阻塞并释放锁。m->lock();
, *signal = true;
, m->unlock();
和sleep_for
。 因此, signal
变为true
。std::unique_lock<std::mutex> lk(*m);
和cv->wait(lk, [&] { return (*signal); });
. 因为signal
是true
,所以这个线程只是通过它。 所以, printf("consumer %d passes this point,\n"; index);
被执行。cv->notify_one();
. 消费者 1 已解锁并检查情况。 因为signal
是ture
,所以 consumer1 可以通过这一点。 因此, consumer1 满足printf
。因此,我的预期结果是
consumer 2 passes this point!
notify one
consumer 1 passes this point!
然而,真正的结果是
consumer 2 passes this point!
notify one
好像consumer1不能通过cv->wait(lk, [&] { return (*signal); });
,即使notify_one()
被调用并且条件得到满足。 我的理解有什么问题吗?
您没有释放consumer
程序中的锁定。 下面的代码符合预期:
#include <thread>
#include <chrono>
#include <condition_variable>
#include <mutex>
void producer(std::mutex* m, std::condition_variable* cv,bool* signal) {
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::unique_lock<std::mutex> lk(*m);
*signal = true;
}
std::this_thread::sleep_for(std::chrono::seconds(3));
cv->notify_all();
printf("notify one\n");
std::this_thread::sleep_for(std::chrono::seconds(5));
}
void consumer(std::mutex*m, std::condition_variable* cv, bool* signal, int index) {
if(index == 2) std::this_thread::sleep_for(std::chrono::seconds(2));
{
std::unique_lock<std::mutex> lk(*m);
cv->wait(lk, [&] { return (*signal); });
}
printf("consumer %d passes this point!\n", index);
std::this_thread::sleep_for(std::chrono::seconds(5));
}
int main() {
bool signal = false;
std::mutex m;
std::condition_variable cv;
std::thread th1(producer, &m, &cv, &signal);
std::thread th2(consumer, &m, &cv, &signal, 1);
std::thread th3(consumer, &m, &cv, &signal, 2);
th1.join();
th2.join();
th3.join();
return 0;
}
注意std::unique_lock<std::mutex> lk(*m);
周围的括号。 提供本地scope。
问题是消费者 2 在进入睡眠状态之前没有释放互斥锁上的锁:
std::unique_lock<std::mutex> lk(*m);
cv->wait(lk, [&] { return (*signal); });
printf("consumer %d passes this point!\n", index); // <-- mutex is still locked here
std::this_thread::sleep_for(std::chrono::seconds(10000));
因此,即使消费者 1 中的条件可能满足,它也无法获取互斥锁上的锁,因为它已经被另一个线程锁定。
与对应的std::lock_guard
相比, std::unique_lock为您提供了更细粒度的控制,包括解锁能力。 您可以做的是在消费者进入睡眠之前添加一个解锁调用,如下所示:
...
lk.unlock();
std::this_thread::sleep_for(std::chrono::seconds(10000));
否则,只有在消费者 2 执行完consumer()
function 后,即长时间休眠后,才会释放互斥锁上的锁。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.