跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 关于 C++ 11 中的 condition_variable. 有一处没想明白。
未分類
4 2 月 2021

关于 C++ 11 中的 condition_variable. 有一处没想明白。

关于 C++ 11 中的 condition_variable. 有一处没想明白。

資深大佬 : V2WT 6

首先根据: The C++ core guideline 的第 42 条中提到:不要在没有条件的情况下等待( Don’t wait without a condition).主要是为了解决:

  • 唤醒丢失
  • 虚假唤醒

下面是范例代码:

#include <condition_variable> #include <iostream> #include <thread>  std::mutex mutex_; std::condition_variable condVar;  bool dataReady{false};  void waitingForWork(){     std::cout << "Waiting " << std::endl;     std::unique_lock<std::mutex> lck(mutex_);     condVar.wait(lck, []{ return dataReady; });   // (4)     std::cout << "Running " << std::endl; }  void setDataReady(){     {         std::lock_guard<std::mutex> lck(mutex_);         dataReady = true;     }     std::cout << "Data prepared" << std::endl;     condVar.notify_one();                        // (3) }  int main(){   std::cout << std::endl;   std::thread t1(waitingForWork);               // (1)   std::thread t2(setDataReady);                 // (2)   t1.join();   t2.join();   std::cout << std::endl; } 

这里再贴一下搜到的资料里 condition_variable 的处理逻辑: wait (lck, pred); 其实等价于 while (!pred()) wait(lck);,它的运行机制如下:

  1. 线程获取 mutex 的锁,然后对 predicate 的结果进行检查: true:线程继续往下执行; false:condVar.wait() 解锁 mutex,然后线程进入等待(阻塞)状态。
  2. 假如 condVar 已经在等待状态,此时得到通知(不管发送线程发送,还是虚假唤醒): 线程进入非阻塞状态,然后重新获取 mutex 的锁。 线程检查 predicate 的结果: true:线程继续往下执行; false:condVar.wait() 解锁 mutex,然后线程进入等待(阻塞)状态。

这里我的问题是: 假设运行步骤是这样:

  1. t2 线程(setDataReady)先执行了。这个时候dataReady = true. 并且 notify_one了。
  2. t1 线程(waitingForWork)里 wait 的 predicate 为 true.直接往下执行了。并不会阻塞在 condVar.wait 的阶段(根据上面的运行机制是这样)。

所以这个时候相当于空白 notify_one了一次。实际上 t1 线程的运行只跟 dataReady有关,而跟 condition_variable 无关了。那么这次的notify_one的信号到底去哪里了呢?

不知道我有没有描述清楚问题。有大佬能解答一下吗?

大佬有話說 (5)

  • 資深大佬 : chuckzhou

    notify_one 会检查是否有 waiter,如果没有,啥也不干就退出了。

  • 主 資深大佬 : V2WT

    @chuckzhou 假设现在有一个 Thread t3 = t2. 这样一次 notify_one(). 因为修改了标志位置。实际上 t2 t3 这两个线程都会执行。那这个 condition_variable 还有什么用呢?

  • 主 資深大佬 : V2WT

    @chuckzhou 啊这是我理解有问题了。多个同时等的时候,应该等到了要把 flag 取反的。 不好意思。。

  • 資深大佬 : chuckzhou

    @V2WT 如果是你说的这种情况,predicate 就不应该这么写。
    一个常见的场景就是生产者和消费者。
    一个线程生产了一个数据,比如把数据放到一个 list 里面,为了提高性能,可能有很多消费者,但是只有一个数据,如果你的 predicate 是 dataReady,那确实会导致消费者都运行,这显然是不对。
    所以你的 predicate 要写成 !list.empty() 这样,第一个线程把数据取走了之后,第二个线程就会继续等待了。

  • 主 資深大佬 : V2WT

    @chuckzhou 是的。后来想想明白了。感谢答复。

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具