Multithreading 使用条件变量的死锁

Multithreading 使用条件变量的死锁,multithreading,c++17,Multithreading,C++17,我有一个关于条件变量的问题 有这个代码吗 #include <iostream> #include <thread> #include <chrono> #include <mutex> #include <condition_variable> std::condition_variable cv; std::mutex mut; int value; void sleep() { std::unique_lock<st

我有一个关于条件变量的问题

有这个代码吗

#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
#include <condition_variable>

std::condition_variable cv;
std::mutex mut;
int value;

void sleep() {
  std::unique_lock<std::mutex> lock(mut);
  // sleep forever
  cv.notify_one();
}

int main ()
{
  std::thread th (sleep);

  std::unique_lock<std::mutex> lck(mut);
  if(cv.wait_for(lck,std::chrono::seconds(1))==std::cv_status::timeout) {
    std::cout << "failed" << std::endl;
  }

  th.join();

  return 0;
}
#包括
#包括
#包括
#包括
#包括
std::条件变量cv;
std::互斥mut;
int值;
虚无睡眠{
std::唯一锁定(mut);
//长眠
cv.通知_one();
}
int main()
{
std::线程th(睡眠);
标准:唯一锁定lck(mut);
如果(cv.wait_for(lck,std::chrono::seconds(1))==std::cv_状态::超时){
标准::cout
为什么在1秒之后还要等待阻塞

你怎么知道主线程曾经到达
cv.wait_for(…)
调用

你问什么还不是100%清楚,但是如果程序从未打印“失败”,你问为什么不打印,那么可能发生的情况是,子线程先锁定互斥体,然后在保持互斥体锁定的同时“永远休眠”。如果发生这种情况,那么主线程将永远无法通过
std::unique_lock lck(mut);

线程th是否需要mut

这要视情况而定。你当然不需要在一个只做“//sleep forever”的线程中锁定互斥对象,但你所询问的线程可能与你所展示的线程不完全相同。也许你是在问应该如何使用wait()和notify()

我无法给出特定于C++的答案,但在大多数编程语言和库中,wait()和notify()都是低级原语,用于非常特定的方式:

“消费者”线程通过执行以下操作进行等待:

mutex.lock();
while ( ! SomeImportantCondition() ) {
    cond_var.wait(mutex);
}
DoSomethingThatRequiresTheConditionToBeTrue();
mutex.unlock()
mutex.lock();
... Do something that makes SomeImportantCondition() return true;
cond_var.notify();
mutex.unlock();
互斥体的用途是保护
SomeImportantCondition()
测试的共享数据。当互斥体被锁定时,不允许其他线程更改
SomeImportantCondition()
返回的值

另外,您可能已经知道这一点,但有些读者可能不知道;
cond_var.wait(mutex)中给出了
mutex
的原因
这是因为等待函数在等待时临时解锁互斥体,然后在返回互斥体之前重新锁定互斥体。解锁是必要的,以便允许生产者线程使条件变为真。需要重新锁定以确保当使用者访问共享线程时条件仍然为真数据

需要注意的第三件事是,如果条件已经为真,消费者不会等待()。一个常见的新手错误是无条件地调用
cv.wait()
,并期望在其他线程中调用
cv.notify()
会将其唤醒。但是
notify()
如果在使用者开始等待之前发生,则不会唤醒使用者线程


编写“producer”更容易。没有任何技术原因说明为什么“producer”不能只调用
cond\u var.notify()
,而不做任何其他事情。但这不是很有用。大多数producer都会这样做:

mutex.lock();
while ( ! SomeImportantCondition() ) {
    cond_var.wait(mutex);
}
DoSomethingThatRequiresTheConditionToBeTrue();
mutex.unlock()
mutex.lock();
... Do something that makes SomeImportantCondition() return true;
cond_var.notify();
mutex.unlock();

唯一真正重要的是,生产者在它接触到由
SomeImportantCondition()
测试的共享数据之前锁定互斥体。一些编程语言允许您在
unlock()之后移动
notify()
调用
打电话。其他人不会。这两种方式都不重要。

什么是永久睡眠?你是想说
简历notify_one()
调用永远不会发生?如果是这样,那么为什么不删除它呢?示例越简单越好。为什么要调用
等待
呢?似乎没有什么需要等待的。互斥锁保护什么?两个线程之间的共享状态是什么?