【问题标题】:Shared atomic variable is not properly published if it is not modified under mutex如果在互斥锁下没有修改共享原子变量,则无法正确发布
【发布时间】:2016-11-04 00:11:55
【问题描述】:

我在http://en.cppreference.com/w/cpp/thread/condition_variable 上阅读有关 std::condition_variable 的信息,但我不明白:

即使共享变量是原子的,也必须在 mutex 以便正确地将修改发布到等待 线程。

如果没有在互斥锁下修改共享原子变量,为什么不能正确发布?如何理解这句话?

在另一页http://en.cppreference.com/w/cpp/atomic/atomic 上有一个声明似乎与第一个声明相矛盾:

如果一个线程写入一个原子对象,而另一个线程读取 从中,行为是明确定义的(有关详细信息,请参阅内存模型 数据竞赛)

【问题讨论】:

  • std::condition_variablestd::atomic 是两个不同的东西。
  • 我想这是因为等待线程通过互斥锁同步(否则它不能“等待”)而不是通过原子变量。
  • 关于stackoverflow.com/a/32978267/2756719的最后一个例子
  • 好吧,如果std::condition_variable 有任何其他内部状态,则需要保护(同步)。

标签: c++ c++11


【解决方案1】:

考虑这个例子:

std::atomic_bool proceed(false);
std::mutex m;
std::condition_variable cv;

std::thread t([&m,&cv,&proceed]()
{
    {
        std::unique_lock<std::mutex> l(m);
        while(!proceed) {
            hardWork();
            cv.wait(l);
        }
    }
});

proceed = true;
cv.notify_one();
t.join();

这里原子共享数据proceed在没有使用互斥体的情况下被修改,之后通知被发送到条件变量。但是有可能在发送通知的那一刻,线程t 并没有等待cv:而是在hardWork() 内部,在此之前检查了proceed 并发现它是错误的。错过了通知。当t 完成hardWork 时,它将继续等待(大概永远)。

如果主线程在修改共享数据proceed之前锁定了互斥锁,则可以避免这种情况。

我认为这就是说“即使共享变量是原子的,也必须在互斥锁下对其进行修改才能正确地将修改发布到等待线程”时的情况。

【讨论】:

  • 即使没有hardWork 也可能发生这种情况。你可以查看proceed,发现是假的,那么proceed可以设置为true,然后notify_one可以调用,然后你可以调用wait。同样,你会等待已经发生的事情。条件变量的整个逻辑是它们与保护共享状态的互斥体一起工作,以提供原子的“解锁和等待”操作。
猜你喜欢
  • 2021-06-10
  • 1970-01-01
  • 1970-01-01
  • 2013-12-17
  • 1970-01-01
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多