C++ 创建/加入线程时的隐式同步

C++ 创建/加入线程时的隐式同步,c++,multithreading,language-lawyer,memory-model,C++,Multithreading,Language Lawyer,Memory Model,考虑到创建/加入线程时隐含的同步:std::atomic,此代码工作所需的x类型的最小帧是什么易失性?什么都没有 #include <thread> #include <cassert> int main() { int x = 123; // *** std::thread( [ & ] { assert( x == 123 ); x = 321; } ).join(); assert( x == 321 ); return 0;

考虑到创建/加入线程时隐含的同步:
std::atomic
,此代码工作所需的
x
类型的最小帧是什么<代码>易失性?什么都没有

#include <thread>
#include <cassert>
int main() {
    int x = 123; // ***
    std::thread( [ & ] { assert( x == 123 ); x = 321; } ).join();
    assert( x == 321 );
    return 0;
}
#包括
#包括
int main(){
int x=123;//***
std::thread([&]{assert(x==123);x=321;}).join();
断言(x==321);
返回0;
}

调用
std::thread
的构造函数是同步的,发生在调用线程函数副本(30.3.1.2/6)之前

thread::join
提供了类似的同步保证:线程的完成发生在
join
返回之前(30.3.1.4/7)

您的代码创建一个线程并立即将其联接。尽管lambda通过引用捕获,但并不存在并发性(代码按顺序运行),而且
std::thread
提供的保证确保您不需要任何特殊帧来保护
x
。这一主张永远不会失败


假设您的代码片段不同,因此您实际上具有某种并发访问权限,那么您将不得不使用
std::atomic
或互斥锁
volatile显然是不够的(巧合除外)。

您需要阅读相关问题。
std::thread([&]{assert(x==123);x=321;})。join()
没有对
x
的并发访问,您可以顺序调用lambda来实现相同的行为<顺便说一句,代码>易失性
从不用于线程安全。我理解,根据规范
易失性
是不够的,因为只有
std::atomic
类型被声明为无数据争用,但是
int
在引擎盖下是什么让它变得活泼呢?我如何识别失败?这是因为在某些平台上,int的四个字节可以写入两个2字节的块,而在其他具有本机32位int的平台上,即使仍然错误,它也会一直工作吗?在某些平台上,
std::atomic
是否只是
int
的别名?这里有一个真正好奇的学习者。@antiduh,不仅仅是阅读或编写变量。使用原子还可以约束重新排序。@antiduh:原子类型及其专门化保证您具有某些(无论您选择哪个)排序保证。也就是说,例如,在原子操作之前,依赖写入(或独立写入)保证全局可见。
volatile
不提供此类保证。它可能“起作用”,但那是巧合。关于写整数,假设主流CPU和正确对齐,你是对的。非原子
int
写入是不可能的。然而,这没有正式的保证,也不可移植,没有定义的顺序,并且RMW操作(例如,
++x
)也是非原子的。