为什么既有std :: condition_variaible的通知和等待功能,都需要锁定的静音

Why do both the notify and wait function of a std::condition_variable need a locked mutex

本文关键字:功能 锁定 等待 通知 std condition 为什么 variaible      更新时间:2023-10-16

在我永远无法理解std::contion_variable s的任务中,我遇到了以下内容。在此页面上说:

void print_id (int id) {
  std::unique_lock<std::mutex> lck(mtx);
  while (!ready) cv.wait(lck);
  // ...
  std::cout << "thread " << id << 'n';
}

之后,它说了:

void go() {
  std::unique_lock<std::mutex> lck(mtx);
  ready = true;
  cv.notify_all();
}

现在,据我了解,这两个功能都会停止在std::unqique_lock行上。直到获得唯一的锁。也就是说,没有其他线程有锁定。

因此,请首先执行print_id功能。唯一的锁将是aquired的,功能将在等待线上停止。

然后执行go函数(在单独的线程上),则该代码将停止在唯一的锁线上。由于MUTEX已被print_id函数锁定。

显然,如果代码是这样,这将行不通。但是我真的看不到我没有到达什么。所以请启发我。

所缺少的是 wait解锁互斥,然后在 cv上等待信号。

它在返回之前再次锁定二线。

您可以通过单击在找到示例的页面上的等待来找到这一点:

在阻止线程的时刻,该功能会自动调用lck.unlock(),允许其他锁定线程继续。

曾经通知(明确地通过某些线程明确),该功能解开并调用lck.lock(),将LCK与调用函数时的状态相同。

您错过了一点点;呼叫 wait() unlocks the mutex。线程在原子上(释放二线 入睡)。然后,当信号唤醒时,它试图重新接触静音(可能阻止);一旦获取它,就可以继续。

请注意,不必将MUTEX锁定用于调用notify_*,仅适用于wait*

要回答提出的问题,这对于您不应出于绩效原因而不应锁定通知的说法似乎是必要的(不是比绩效重要吗?):锁定"等待",并始终锁定"通知"的建议是保护用户免受数据和逻辑种族的侵害。如果没有" GO"锁定,您发布的程序将立即在"准备就绪"上进行数据竞赛。但是,即使准备就绪即使已经同步(例如原子),您也会有一场逻辑竞赛,没有错过的通知,因为如果没有" go"中的锁 检查"就绪"和的检查 原子变量本身上的同步不足以防止这种情况。这就是为什么赫尔格林德在不握住锁的情况下通知时会警告的原因。在某些有一些边缘案例中,实际上不需要静音锁定。在所有这些情况下,都需要事先进行双向同步,以便生产线程可以确保其他线程已经在等待。IMO这些案件仅适用于专家。实际上,我已经看到一位专家,谈论了多线程,弄错了 - 他认为原子柜台就足够了。也就是说,等待始终是正确性的(或至少是一个与等待的原子能的操作),这就是为什么标准库强制执行它并在输入等待时解锁Mutex的原因。p> POSIX条件变量与Windows事件不同,而不是"愚蠢的",因为它们是无状态的(除了了解等待线程外)。在那里使用锁定的锁定的建议是保护您免受最严重和最常见的螺丝钉的侵害。您可以使用Mutex 条件var bool变量构建类似Windows的状态事件,如果您愿意。