是否确实需要在互斥下修改与条件变量相关的共享变量?

请考虑以下来自cppreference的关于std::condition_variable的引用:

condition_variable类是一个同步原语,可用于同时阻止一个或多个线程,直到另一个线程都修改了一个共享变量 condition ),并通知condition_variable

打算修改变量的线程必须

  1. 获取std::mutex(通常通过std::lock_guard
  2. 在锁定状态下执行修改
  3. notify_one上执行notify_allstd::condition_variable(不需要为通知而持有锁)

即使共享变量是原子变量,也必须在互斥锁下对其进行修改,以便将修改正确发布到等待的线程中。

此方法的示例性典型方案如下:

// shared (e.d.,global) variables:
bool proceed = false;
std::mutex m;
std::condition_variable cv;
// thread #1:
{
   std::unique_lock<std::mutex> l(m);
   while (!proceed) cv.wait(l); // or,cv.wait(l,[]{ return proceed; });
}
// thread #2:
{
   std::lock_guard<std::mutex> l(m);
   proceed = true;
}
cv.notify_one();

但是,this question中的@Tim提出了(一种学术上的)替代方案:

std::atomic<bool> proceed {false}; // atomic to avoid data race
std::mutex m;
std::condition_variable cv;
// thread #1:
{
   std::unique_lock<std::mutex> l(m);
   while (!proceed) cv.wait(l);
}
// thread #2:
proceed = true; // not protected with mutex
{ std::lock_guard<std::mutex> l(m); }
cv.notify_one();

由于proceed共享变量(在这种情况下是原子的)未在互斥锁下进行修改,因此显然不满足上述cppreference引用的要求。

问题是该代码是否正确。我认为是因为,

  1. 第一个选项是!proceed中的while (!proceed)被评估为 false 。在这种情况下,根本不会调用cv.wait(l);

  2. 第二个选项是将!proceed中的while (!proceed)评估为 true 。在这种情况下,cv.notify_one()不会发生,直到线程#1进入cv.wait(l);

我在这方面是否缺少某些东西或cppreference是否错误?(例如,是否涉及一些重新排序问题?)


然后,如果将proceed = true;更改为proceed.store(true,std::memory_order_relaxed);怎么办?

youngssss 回答:是否确实需要在互斥下修改与条件变量相关的共享变量?

暂时没有好的解决方案,如果你有好的解决方案,请发邮件至:iooj@foxmail.com
本文链接:https://www.f2er.com/2377888.html

大家都在问