zyfforlinux

专注linux内核,系统编程,C++服务器端编程,golang ,python/bash脚本编程,DevOps,分布式...

Item39 Consider void futures for one-shot event communication

   有的时候对于一个任务来说,希望有一种机制可以和另外一个任务进行通信,尤其是那种异步运行的任务,并且会出现一种特定事件的任务,另外一个任务需要等到这个事件的发生才能继续运行,典型的,可以是等待一个重要的数据结构进行初始化,或者是等待一个计算阶段完成,又或者是检测一个重要的值。那么什么样的方式可以处理好这种线程间的通信呢?

​一个很明显的方法就是使用条件变量,一个任务就等待条件变量上,等待特定事件完成后被唤醒即可,部分代码如下:

// cv表示一个事件,m是用来保护这个条件变量
std::condition_variable cv;
std::mutex m;

// 进行事件探测和通知
.....                   // 探测事件是否发生
cv.notify_one();        // 进行事件的通知

   尽管使用条件变量可以达到我们想要的效果,但是未免有点复杂,等待事件的时候还需要使用mutex对条件变量进行保护,对于一些比较简单的事件来说没未免显得过重了。此外使用条件变量还需要考虑下面几个问题:

  1. 如果探测的任务在条件变量wait之前就进行了通知,那么等待事件的任务就会hang住
  2. 条件变量的wait会出现虚假唤醒的问题,尽管可以通过添加一个检测条件,在被虚假唤醒的时候,再次检测指定事件是否发生,但是有的时候却没有一种可行的方式用来检测。

   假设我们可以处理好上述问题,但是使用条件变量仍然会带来不少的开销,比如:在特定事件完成后必须要进行通知,接受到通知后还需要再次检查事件是否完成。这显然都是一些多余的操作。对于这个问题可以使用我们在Item38中提到的std::promisestd::future来完成,这两者构成了一个简单的channel用于通信,特定事件完成后只需要往std::promise写入一个空值来表明事件完成,那么阻塞在std::future对象上的任务就会被唤醒,部分代码如下:

std::promise<void> p;
p.set_value();  // 事件完成,进行通知

p.get_future().wait(); // 等待事件完成

   虽然std::promisestd::future这种方式显得更加简单,但是这不代表它是完美的方案,这种方式需要维护一个共享状态,需要在堆上分配存储,有分配和释放的开销,并且这种事件通知也是一次性的,而条件变量的方式可以多次触发事件。

阅读更多

扫码向博主提问

去开通我的Chat快问

zhangyifei216

博客专家

linux,C++,Golang
  • 擅长领域:
  • Linux
  • C++
  • Golang
  • Rust
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangyifei216/article/details/71036247
所属专栏: Effective Modern C++解读
上一篇Item38 Be aware of varying thread handle destructor behavior
下一篇Item40 Use std::atomic for concurrency, volatile for specific memory
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭