c++ - thread::join 上是否存在具有同步关系的隐式内存屏障?

标签 c++ multithreading c++11 memory-barriers memory-fences

我有一个工作代码,它启动多个线程来执行某些操作,如果其中任何一个失败,它们会将共享变量设置为false

然后主线程加入所有工作线程。模拟看起来大致如下(我注释掉了可能的修复,我不知道是否需要):

#include <thread>
#include <atomic>
#include <vector>
#include <iostream>
#include <cassert>

using namespace std;

//atomic_bool success = true;
bool success = true;

int main()
{
    vector<thread> v;
    for (int i = 0; i < 10; ++i)
    {
        v.emplace_back([=]
        {
            if (i == 5 || i == 6)
            {
                //success.store(false, memory_order_release);
                success = false;
            }
        });
    }
    for (auto& t : v)
        t.join();

    //assert(success.load(memory_order_acquire) == false);
    assert(success == false);

    cout << "Finished" << endl;
    cin.get();
    return 0;
}

即使其中一个工作线程将成功变量设置为false,主线程是否有可能将其读取为true

我发现 thread::join() 是一个完整的内存屏障 ( source ),但这是否意味着与以下读取 synchronized-with 关系em>success 来自主线程的变量,这样我们就可以保证获得最新的值?

在这种情况下,我发布的修复程序(在注释代码中)是否必要(或者如果此修复程序错误,则可能需要另一个修复程序)?

是否有可能对成功变量的读取进行优化(因为它不是 volatile 的),并且无论是否存在隐式内存屏障,我们都将获得旧值在 thread::join 上?

代码应该可以在多种体系结构上工作(记不清所有体系结构,我面前没有 makefile),但至少有 x86、amd64、itanium、arm7。

感谢您对此提供的任何帮助。

编辑:我修改了该示例,因为在实际情况下,多个线程可以尝试写入 success 变量。

最佳答案

上面的代码代表了数据竞争,使用 join 无法改变这一事实。如果只有一个线程写入该变量,那就没问题了。但是您有两个线程写入它,它们之间没有同步。这是一场数据竞赛。

join 只是表示“该线程操作的所有副作用都已完成,现在您可以看到”。这不会在该线程和除您自己的线程之外的任何线程之间创建排序或同步。

如果你使用了atomic_bool,那么它就不是UB;它肯定是假的。但因为存在数据竞争,所以你得到的是纯粹的 UB。它可能是真恶魔,也可能是假恶魔,或者是鼻恶魔。

关于c++ - thread::join 上是否存在具有同步关系的隐式内存屏障?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42175207/

相关文章:

c++ - load-acquire 应该立即看到 store-release 吗?

c++ - 参数包函数参数可以默认吗?

C++ std::tr1::hash::operator() 未定义?

c++ - 如何在 C++ 中的 if 语句中检查 lambda 的返回值?

c++ - 如何在 x64 平台上使用 HTMLHelpCtrl.ocx ActiveX 控件

c++ - C++ 中 main 函数返回值的约定是什么?

python - Python 中更复杂的并行 for 循环

ios - IOS重启主线程

multithreading - "thread"(真的)是什么?

c++ - 列表初始化的形式