在C++scott-meyers中检测事件时使用的条件变量

condition variable usage in detecting an event in C++ scott meyers

本文关键字:条件 变量 C++scott-meyers 检测 事件      更新时间:2023-10-16

我正在阅读Scott Meyers的Effective Modern C++中关于条件变量的书,下面的书是文本。

std::condition_variable   cv
std::mutex                m
T1 (detecting task)
...
cv.notify_one();

T2 (reacting task)
...
{
  std::unique_lock<std::mutex> lk(m);
  cv.wait(lk);
  ...
}

以下是作者提到的

Mutex用于控制对共享数据的访问,但它完全检测和反应任务可能不需要调解。例如,检测任务可能负责初始化全局数据结构,然后将其转换为反应任务以供使用。如果检测任务从未访问过数据结构在初始化它之后,如果反应任务以前从未访问过它检测任务表明它已准备好,两个任务将保留通过程序逻辑互相让开。没有必要用于互斥。

在上面的文本中,我很难理解

  1. 作者所说的"通过程序逻辑,两个任务将互不妨碍"是什么意思?

  2. 作者所说的不需要互斥是什么意思?

Mutex用于解决竞争条件,例如:

当两个或多个线程可以访问共享数据,并且它们试图同时更改时,就会出现竞争情况

在你的情况下,这不会发生,因为对你的结构所做的操作将在不同的时间框架内完成,即:不会造成任何比赛条件。由于不需要两个线程同时写入,因此不需要互斥。

还要考虑的是,当你有"检查然后行动"(例如,如果值是X,则"检查",然后"行动"来做取决于值是X的事情),而另一个线程对"检查"answers"行动"之间的值做了一些事情时,大多数问题都会出现。

检测任务和反应任务都访问相同的数据,但程序逻辑保证它们永远不会同时访问该数据。因此,它们不需要互斥(或任何其他机制)来阻止对数据的并发访问,因为这种并发访问是通过其他方式阻止的。另一种方法是程序逻辑。

"程序逻辑"是指程序的控制流程。我将稍微重新格式化代码:

Data shared_data;
std::condition_variable cv;
std::mutex m;
void detecting_task()
{
  initialise(shared_data);
  cv.notify_one();
}
void reacting_task()
{
  {
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk);
  }
  process(shared_data);
}

即使detecting_taskreacting_task同时启动,您也可以看到它们不可能同时作用于shared_data。程序逻辑使得detecting_task仅在cv被通知之前接触数据,并且reacting_task仅在cv被通知之后接触数据。因此,它们不可能重叠,因此不需要通过互斥来保护shared_data

从本质上讲,文本说:当两个线程不访问任何共享资源时,就不需要同步访问资源。也就是说,如果每个线程只使用自己的数据结构,而没有其他线程访问它们,那么就不需要通过互斥锁进行任何锁定——没有其他线程会访问相应的资源。

在给定上下文的情况下,似乎描述了一个简单的消息传递系统,即使用互斥和条件变量的东西,它完成了所有必要的同步:"检测线程"注意到一些东西,并通过消息传递系统向"反应线程"发送通知。它们之间唯一共享的是消息传递对象。

我也不完全理解引文。如果您不保护共享数据,那么互斥锁对于内存访问是不必要的。这可能意味着,检测任务将不需要锁定互斥锁。

但是,c++11 condition_variable需要一个互斥锁才能工作。这是因为,至少一些底层操作系统实现需要互斥,比如pthreads

请参阅:为什么pthreads的条件变量函数需要互斥?