c++ - 调用线程会在 thread.join() 之后看到对局部变量的修改吗?

标签 c++ c++11 concurrency thread-safety memory-model

在最简单的示例中,假设我有一个启动线程的函数,该线程又将局部变量的值设置为 true。我们加入线程,然后离开函数。

bool func() {
    bool b = false;
    std::thread t([&]() { b = true; }); 
    t.join();
    return b;
}

这个函数会返回 true,还是未定义行为?

最佳答案

是的,它必须返回 true。

[thread.thread.member]

void join();

4 Effects: Blocks until the thread represented by *this has completed.

5 Synchronization: The completion of the thread represented by *this synchronizes with ([intro.multithread]) the corresponding successful join() return.

所以由句柄表示的线程的执行,以及相关的副作用在 join 返回到调用上下文之前完成。

例子

让我们看一下两个函数,它们的区别仅在于它们加入线程的时间:

int count_A() {
    int counter = 0;
    bool flag(true);
    auto t = std::thread([&]{flag = false;});

    while(flag) {    // infinite loop - flag never synchronized
        ++counter;
    }
    t.join();        // joins thread after loop exits
    return counter;
}
int count_B() {
    int counter = 0;
    bool flag(true);
    auto t = std::thread([&]{flag = false;});

    t.join();       // joins thread before loop, forcing synchronization
    while(flag) {
        ++counter;
    }
    return counter;
}

-O3 优化下使用 g++ 8.2 版编译时,调用 count_A 会导致无限循环,因为编译器假定 flag 始终为真.

另一方面,调用 count_B 只会返回值 0。因为在thread.join()之后检查了flag的值,重新加载了它的值,而flag是false所以while循环不执行。

请注意,如果 flag 更改为 atomic_bool,则 count_A 具有递增计数器的预期行为,直到将标志设置为false,函数不会进入无限循环(而是在 flag 被子线程设置为 false 时返回)。

关于c++ - 调用线程会在 thread.join() 之后看到对局部变量的修改吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55932983/

相关文章:

c++ - 并发的 C++03 内存模型是什么?

c++ - "if" "elseif" "else"语句有哪些好的做法

c++ - 将 resize() 调整为更小的尺寸是否会丢弃之前 reserve() 所做的保留?

c++ - 什么是 "rvalue reference for *this"?

java - 并发程序中的伪随机性

java - 如何以线程安全的方式填充字符串映射和另一个映射?

c++ - 整数常量上的错误后缀 Ui64 无效

c++ - 菜鸟,帮忙做个对象

c++ - 初始化一个全局的 const POD 结构;针对特定成员

c++ - 转换运算符 template<typename T> T&&() 是否有意转换为右值?