在x86-64多核机器上读取和写入C++ Atomic中的int

Jul*_*ian 3 c++ multithreading atomic cpu-cache

我读过这个,我的问题很相似但有点不同.

注意,我知道C++ 0x并不能保证这一点,但我特别要求像x86-64这样的多核机器.

假设我们有2个线程(固定到2个物理内核)运行以下代码:

// I know people may delcare volatile useless, but here I do NOT care memory reordering nor synchronization/
// I just want to suppress complier optimization of using register.
volatile int n; 

void thread1() {
    for (;;)
        n = 0xABCD1234;
        // NOTE, I know ++n is not atomic,
        // but I do NOT care here.
        // what I cares is whether n can be 0x00001234, i.e. in the middle of the update from core-1's cache lines to main memory,
        // will core-2 see an incomplete value(like the first 2 bytes lost)?
        ++n; 
    }
}

void thread2() {
    while (true) {
        printf('%d', n);
    }
}
Run Code Online (Sandbox Code Playgroud)

是否有可能线程2 n看起来像是0x00001234,即在从core-1的缓存行更新到主内存的过程中,core-2会看到一个不完整的值吗?

我知道一个4字节int肯定适合一个典型的128字节长的高速缓存行,如果它int确实存储在一个高速缓存行内,那么我相信这里没有问题......但是如果它超过高速缓存行边界呢?即会是possbile,有些char已经坐高速缓存行,这使得第一部分中n的一个高速缓存行和下一行的另一部分?如果是这种情况,那么core-2可能有机会看到一个不完整的值,对吧?

另外,我认为除非将每个charshort其他less-than-4-bytes类型填充为4字节长,否则永远不能保证单个int不通过缓存行边界,不是吗?

如果是这样,那么int在x86-64多核机器上,一般情况下甚至设置单个也不保证是原子的吗?

我得到了这个问题,因为当我研究这个主题时,不同帖子中的各个人似乎都同意这一点,只要机器架构是正确的(例如x86-64),设置int应该是原子的.但正如我上面提到的那样,不成立,对吧?

UPDATE

我想提出一些问题的背景知识.我正在处理一个实时系统,它正在对一些信号进行采样并将结果放入一个全局int中,这当然是在一个线程中完成的.在另一个线程中,我读取了这个值并处理它.我不关心set和get的排序,我只需要一个完整的(相对于一个被破坏的整数值)值.

nwp*_*nwp 7

x86保证这一点.C++没有.如果你写x86程序集你会没事的.如果你编写C++,那就是未定义的行为.由于您无法推断未定义的行为(它毕竟是未定义的),您必须降低并查看生成的汇编程序指令.如果他们做你想做的事情那么这很好.但请注意,当您更改编译器,编译器版本,编译器标志或可能更改优化器行为的任何代码时,编译器会更改生成的程序集,因此您将不断检查汇编程序代码以确保它仍然正确.

更简单的方法是使用std::atomic<int>它将保证生成正确的汇编程序指令,因此您不必经常检查.

  • 具体来说,x86 保证*正确对齐的值*。现在你必须花一些功夫才能得到一个未对齐的“int”,但这是可能的。 (2认同)

Bo *_*son 6

另一个问题是关于变量“正确对齐”的。如果它越过缓存行,则该变量正确对齐。int除非您明确要求编译器打包结构,否则An 不会这样做。

您还假设使用volatile int优于atomic<int>。如果volatile int是在平台上同步变量的理想方法,那么库实现者肯定也会知道这一点并存储一个volatile xinside atomic<x>

不需要atomic<int>仅仅因为它是标准的就必须特别慢。:-)


Bat*_*eba 5

为什么这么担心?

依靠你的实施.std::atomic<int>将在您的平台上减少为intif intis atomic(如果正确对齐,则在x86-64中).

int如果我是你,我也会担心代码溢出的可能性(这是未定义的行为).

换句话说std::atomic<unsigned>,这里是合适的类型.

  • 这不是那么简单.原子增量比普通增量慢得多.并且在x86上访问对齐的int是原子的(对齐的int永远不会跨越高速缓存行).因此,如果OP知道他在做什么(即n ++是否是原子无关紧要),在这种情况下不使用原子就可以了. (3认同)