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

展开阅读全文

Windows版YOLOv4目标检测实战:训练自己的数据集

04-26
©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值