4

我有一个代码在工作,它启动多个执行某些操作的线程,如果它们中的任何一个失败,它们将共享变量设置为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),但这是否意味着与以下从主线程读取成功变量的同步关系,以便我们保证获得最新值?

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

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

该代码应该适用于多种架构(不记得所有架构,我面前没有makefile)但至少有x86,amd64,itanium,arm7。

感谢您对此的任何帮助。

编辑:我已经修改了示例,因为在实际情况下,一个线程可以尝试写入成功变量。

4

1 回答 1

2

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

join只是意味着“该线程操作的所有副作用都已完成并且现在对您可见。” 这不会在该线程和除您自己的线程之外的任何线程之间创建排序或同步。

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

于 2017-02-11T15:23:03.110 回答