将相同的值写入相同的内存位置会导致数据竞争吗?

ybu*_*ill 14 c++ memory multithreading synchronization race-condition

请考虑以下代码,将相同的值写入多个线程的相同内存位置:

void f(int* buf, int n, int* p) {
    for(int i = 0; i < n; i++)
        buf[i] = i;
    *p = buf[n/2];
}

void g(int* buf, int n) {
    int x1, x2;
    thread t1(f, buf, n, &x1);
    thread t2(f, buf, n, &x2);
    t1.join();
    t2.join();
    assert(x1 == x2);
}
Run Code Online (Sandbox Code Playgroud)

虽然它很有意思,但我不太关心标准给出的保证,因为我猜它没有给出.我真正关心的是上述代码在真实世界多处理器硬件上的行为.是否assert总是通过或有任何竞争条件,缓存同步问题等的机会.?

TJD*_*TJD 8

有一场比赛,但在你的例子中,两个线程都会将相同的值写入相同的地址.由于您没有进行任何读取 - 修改 - 写入,而只是编写预定的数字,因此在大多数情况下这是安全的.编写int将是大多数系统上的原子指令.例外情况是,如果您在使用一系列指令存储int的8位微处理器上运行此代码.在这种情况下,它也可能仍然有效,但取决于执行多字节存储的库代码的实现.


Max*_*kin 6

当一个线程所做的写入的影响可被另一个线程观察时,关于多线程的内存模型会受到关注.在您发布的代码中,两个线程都将相同的值写入相同的内存位置,因此无论哪个线程的写入buf[n/2]读取都无关紧要.

现代处理器采用高速缓存一致性协议,例如MESI,因此当线程同时写入缓冲区时,CPU之间会发送大量消息来同步保存缓冲区的高速缓存行,使其运行速度比非高速运行慢得多.并发场景(错误共享效果).

这里写入是否为原子并不重要,因为两个线程都将相同的值写入相同的内存位置.有一场比赛,但是哪个线程获胜并不重要,因为即使部分写入,观察到的值也会相同.