例如:
struct Foo { // whatever Foo can hold }; struct Bar { void buildFoo() { auto tmp = new Foo; // do some stuff on tmp,or not foo = tmp; } Foo* foo; };
现在,让一些线程通过一个Bar实例使用foo,以及调用Bar :: buildFoo()的其他线程有什么后果?
解决方法
不,同时修改/访问raw2指针不能保证是c中的原子操作.
C标准表示如果一个线程修改内存位置而另一个线程修改/访问相同的内存位置,则存在数据争用,如果存在这样的数据争用,则程序会受到未定义的行为的影响.
[intro.multithread]
4)Two expressions evaluations conflict if one of them modifies a memory location (1.7) and the other one accesses or modifies the same memory location.
…
21)The execution of a program contains a data race if it contains two conflicting actions in different threads,at least one of which is not atomic,and neither happens before the other. Any such dat race results in undefined behavior.
1. raw未包含在std :: atomic< Foo *>或等效物中.
特定于实现的行为(Windows 32/64位)
在Windows下,它保证对正确对齐的32位变量的读/写始终是原子的,正如您之前引用的question/answer链接的the article所述.
在64位窗口上访问正确对齐的64位变量也是原子的.
Interlocked Variable Access – 07002
Simple reads and writes to properly-aligned 32-bit variables are atomic operations. In other words,you will not end up with only one portion of the variable updated; all bits are updated in an atomic fashion.
However,access is not guaranteed to be synchronized. If two threads are reading and writing from the same variable,you cannot determine if one thread will perform its read operation before the other performs its write operation.
这是什么意思?
标准说了一件事,而微软的文档说另一个……我们要信任和合作?这当然取决于我们在做什么.
如果我们正在为Windows平台开发soley,我们可以阅读所使用的编译器在代码生成方面所保证的内容并从那里开始,但是如果我们想要编写可能在不同平台下编译和运行的代码,那么唯一要做的就是正确信任是标准.
所以在windows下工作时我可以安全地交换32位变量吗?
如果你通过“交换”意味着一个操作,如下面的代码片段中写的内容,答案是否,但如果你的意思是“分配”答案是肯定的.
void swap (int& a,int& b) { int tmp = a; a = b; b = tmp; } int main () { int x = 1; int y = 2; swap (x,y); }
上面的代码片段(或前面提到的文档)中没有任何内容表明这将是一个原子操作,当查看我们的交换实现时,我们很容易看到操作未正确同步.
在Windows下读取/写入单个32位变量是安全的,但是在上面没有什么可以保证当我们处于交换中间时x和y都没有值2.
但是,保证x永远不会包含前一个x中50%的字节和y中50%的字节,或类似的..个别写入是原子的.