3

我正在阅读 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);

  ...
}

这里作者提到如下

互斥体用于控制对共享数据的访问,但检测和反应任务完全有可能不需要这种中介。例如,检测任务可能负责初始化一个全局数据结构,然后将其交给反应任务使用。如果检测任务在初始化后从未访问过数据结构,并且如果反应任务在检测任务指示它已准备好之前从未访问过它,则这两个任务将通过程序逻辑相互避开。不需要互斥锁。

在上面的文字我很难理解

  1. 作者所说的“两个任务将通过程序逻辑相互隔离”是什么意思?

  2. 作者不需要互斥锁是什么意思?

4

4 回答 4

2

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

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

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_task同时reacting_task启动,您也可以看到它们不可能shared_data同时起作用。程序逻辑是detecting_task只接触通知之前的数据,只接触通知 之后的数据。所以它们不可能重叠,因此不需要互斥锁保护。cvreacting_task cvshared_data

于 2015-12-03T12:34:54.880 回答
2

互斥锁用于解决竞争条件,例如:

当两个或多个线程可以访问共享数据并尝试同时更改它时,就会出现竞争条件

在您的情况下,这不会发生,因为在您的结构上完成的操作将在不同的时间范围内完成,即:不会导致任何竞争条件。由于您没有两个线程同时写入,因此您不需要互斥锁。

还要考虑当你有“check-then-act”时出现大多数问题(例如,如果值是 X,则“检查”,然后“act”做一些取决于值是 X 的事情)并且另一个线程对该值做一些事情在“检查”和“行为”之间。

于 2015-12-03T11:51:54.773 回答
1

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

给定上下文,它似乎是一个简单的消息传递系统,即使用互斥锁和条件变量的事物,它被描述为执行所有必要的同步:“检测线程”注意到某事并通过消息传递系统发送通知给“反应线程”。它们之间唯一共享的是消息传递对象。

于 2015-12-03T11:56:41.743 回答
0

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

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

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

于 2015-12-03T12:08:12.527 回答