在没有同步或原子性的情况下访问不同线程中的 64 位变量

Accessing a 64-bit variable in different threads without synchronization or atomicity

我有两个线程共享一个 uint64_t 变量。第一个线程只是从变量中读取,而另一个线程只是写入。如果我不使用 mutex/spinlock/atomic 操作等来同步它们,是否有可能从写入线程中读取另一个值?读取由写入线程写入的旧值并不重要。

举个例子,写线程增加0到100之间的变量,读线程打印这个值。那么,是否有可能在屏幕上看到不同于 [0-100] 范围的值。目前我没有看到任何不同的值,但我不确定它是否会导致竞争条件。

提前致谢。

在 64 位处理器上,一次传输 64 位数据,因此您会看到逻辑上一致的值,即您不会看到写入前的 32 位和写入后的 32 位。这显然不适用于 32 位处理器。

您会看到的问题是,如果两个线程 运行 在不同的内核上,读线程将看不到写线程所做的更改,直到写线程的内核刷新其缓存.此外,优化可能会使任何一个线程都懒得在循环中读取内存。例如,如果您有:

uint64_t x = 0;

void increment()
{
    for (int i = 0 ; i < 100 ; ++i)
    {
        x++;
    }
}

编译器可能会生成代码,在循环开始时将 x 读入寄存器,直到循环退出才将其写回内存。你需要像 volatile 和内存屏障这样的东西。

如果你对这样的变量有竞争条件,那么所有不好的事情都会发生。

现代 C 的正确工具是原子。只需声明您的变量

uint64_t _Atomic counter;

然后,您的所有操作(加载、存储、递增...)都将是原子的,即不可分割、不可中断和可线性化。不需要互斥锁或其他保护机制。

这已在 C11 中引入,最近的 C 编译器(例如 gcc 和 clang)现在开箱即用地支持它。