是 std::condition_variable 线程安全的

Is std::condition_variable thread-safe?

本文关键字:线程 安全 variable std condition      更新时间:2023-10-16

我有一些这样的代码:

std::queue<myData*> _qDatas;
std::mutex _qDatasMtx;

发电机功能

void generator_thread()
{
  std::this_thread::sleep_for(std::chrono::milliseconds(1));
  {
    std::lock_guard<std::mutex> lck(_qDatasMtx);
    _qData.push(new myData);
  }
  //std::lock_guard<std::mutex> lck(cvMtx); //need lock here?
  cv.notify_one();
}

消费者功能

void consumer_thread()
{
  for(;;)
  {
    std::unique_lock lck(_qDatasMtx);
    if(_qDatas.size() > 0)
    {
       delete _qDatas.front();
       _qDatas.pop();
    }
    else
      cv.wait(lck);
  }
}

因此,如果我有几十个生成器线程和一个消费线程,在每个线程中调用 cv.notify_one() 时是否需要互斥锁?

std::condition_variable线程安全吗?

在每个线程中调用cv.notify_one()时是否需要mutex锁?

std::condition_variable线程安全吗?

是的


调用wait时,您会传递一个锁定的mutex该该立即解锁以供使用。调用notify时,您不会使用相同的mutex锁定它,因为将要发生的事情(在链接中详细说明):

  1. 通知
  2. 正在等待的唤醒线程
  3. 锁定互斥锁以供使用

std::condition_variable

在 std::condition_variable 上执行notify_one或notify_all(无需按住锁定进行通知)

和从std::condition_variable::notify_all

通知线程不需要将锁与等待线程持有的锁锁保持在同一互斥锁上;


关于您的代码片段:

//std::lock_guard<std::mutex> lck(cvMtx); //need lock here?
cv.notify_one();

不,你不需要那里的锁。

notify_one可以从多个线程调用,而无需锁定。

但是,为了使正常操作正常工作并且没有通知"溜走"的机会,您必须在修改虚假唤醒保护和/或打包条件变量检查读取的点和通知一个点之间锁定条件变量

您的代码似乎通过了该测试。 但是,此版本更清晰:

std::unique_lock lck(_qDatasMtx);
for(;;) {
  cv.wait(lck,[&]{ return _qDatas.size()>0; });
  delete _qDatas.front();
  _qDatas.pop();
}

它减少了虚假解锁/重新锁定。