指针地址交换总是在C++中进行原子操作吗?

mis*_*why 8 c++ windows multithreading

关于这个问题是否存在32位变量无法正确对齐并提供答案的情况,我可以假设在Windows平台下工作时我可以交换地址而没有任何副作用吗?

例如:

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;
};
Run Code Online (Sandbox Code Playgroud)

现在,让一些线程foo通过实例Bar和其他线程调用会产生什么后果Bar::buildFoo()

Fil*_*efp 10

C++标准

,同时修改/访问原始2指针不能保证是c ++中的原子操作.

C++标准规定,如果一个线程修改内存位置而另一个线程修改/访问相同的内存位置,则存在数据争用,如果存在这样的数据争用,则程序会受到未定义的行为的影响.

[ intro.multithread ]

4)如果其中一个修改了内存位置(1.7)而另一个访问或修改了相同的内存位置,则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)程序的执行包含数据竞争,如果它在不同的线程中包含两个冲突的动作,其中至少有一个不是原子的,并且都不会发生在另一个之前.任何此类数据争用都会导致未定义的行为.

1. 原料是在不被包裹在std::atomic<Foo*>,或等同物.


特定于实现的行为(Windows 32/64位)

在Windows下,它保证对正确对齐的 32-bit变量的读/写始终是原子的,正如您之前引用的问题/答案链接的文章所述.

访问正确对齐的64-bit变量在64-bitWindows 上也是原子的.

互锁变量访问 - http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx

对正确对齐的32位变量的简单读取和写入是原子操作.换句话说,您最终只会更新变量的一部分; 所有位都以原子方式更新.

但是,不保证访问同步.如果两个线程正在从同一个变量读取和写入,则无法确定一个线程是否会在另一个线程执行其写入操作之前执行其读取操作.


这是什么意思?

标准说了一件事,而微软的文档说另一个......我们要信任和合作?这当然取决于我们在做什么.

如果我们正在为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);
}
Run Code Online (Sandbox Code Playgroud)

上面的片段(或前面提到的文档)中的任何内容都没有说这将是一个原子操作,当swap我们查看我们的实现时,我们很容易看到操作没有正确同步.

读/写一个32位的变量是windows下的安全,但在上面没有任何东西可以保证,无论xy不具有价值2,当我们在我们中间swap.

但是,保证x永远不会包含前一个字节的x50%和50%的字节y,或类似的......个别写入是原子的.