c++ - 在 C++ 中递增和递减全局变量时的竞争条件

标签 c++ concurrency race-condition

我找到了一个我能够在 linux 中的 g++ 下重现的竞争条件示例。我不明白的是操作顺序在此示例中的重要性。

int va = 0;

void fa() {
    for (int i = 0; i < 10000; ++i)
        ++va;
}

void fb() {
    for (int i = 0; i < 10000; ++i)
        --va;
}

int main() {
    std::thread a(fa);
    std::thread b(fb);
    a.join();
    b.join();
    std::cout << va;
}

如果我使用 va = va + 1;,我可以理解顺序很重要,因为 RHS va 可能在返回指定的 LHS 之前发生变化va。有人可以澄清一下吗?

最佳答案

标准说(引用最新草案):

[intro.races]

Two expression evaluations conflict if one of them modifies a memory location ([intro.memory]) and the other one reads or modifies the same memory location.

The execution of a program contains a data race if it contains two potentially concurrent conflicting actions, at least one of which is not atomic, and neither happens before the other, except for the special case for signal handlers described below. Any such data race results in undefined behavior.

您的示例程序存在数据竞争,并且程序的行为未定义。


What I don't understand is how the order of operations matter in this example.

操作顺序很重要,因为操作不是原子操作,它们读取和修改相同的内存位置。

can undertand that the order matters if I had used va = va + 1; because then RHS va could have changed before getting back to assigned LHS va

这同样适用于增量运算符。抽象机将:

  • 从内存中读取一个值
  • 增值
  • 将一个值写回内存

那里有多个步骤可以与另一个线程中的操作交错。

即使每个线程只有一个操作,也不能保证定义良好的行为,除非这些操作是原子的。


C++ 范围之外的注意事项:CPU 可能只有一条指令用于递增内存中的整数。比如x86就有这样的指令。它可以以原子方式和非原子方式调用。除非您在 C++ 中显式使用原子操作,否则编译器使用原子指令是一种浪费。

关于c++ - 在 C++ 中递增和递减全局变量时的竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57793739/

相关文章:

c++ - 所有带有 "recursion"的 child 的静态变量

c++ - 使用 Visual Studio 2010 的 CATCH 单元测试套件

java - 如何理解嵌套监视器导致死锁?

c++ - 重印二维数组素因子

java - 使用Thread.yield()时这三个线程不轮流?

java: race conditions - 有没有办法确保几行代码一起执行?

javascript - 如何在 NodeJS 中编写同步块(synchronized block)

c++ - cout 中的函数调用顺序

sql - Redshift 中选择查询的并发性

c++ - 如何检索当前事件窗口光标下的单词?