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

时间:2018-02-01 11:46:41

标签: multithreading mutex atomicity

我有两个共享uint64_t变量的线程。第一个线程只是从变量读取而另一个线程只是写入。如果我不使用互斥锁/自旋锁/原子操作等同步它们,是否有可能从写入线程中读取另一个值?读取通过编写线程编写的旧值并不重要。

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

提前致谢。

2 个答案:

答案 0 :(得分:3)

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

您将看到的问题类似于,如果两个线程在不同的核心上运行,则读取线程将不会看到写入线程所做的更改,直到写入线程的核心刷新其缓存。此外,优化可能使得任何一个线程在循环中根本不打算读取存储器。例如,如果您有:

uint64_t x = 0;

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

编译器可能会生成在循环开始时将x读入寄存器的代码,并且在循环退出之前不会将其写回内存。你需要像volatile和记忆障碍这样的东西。

答案 1 :(得分:2)

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

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

uint64_t _Atomic counter;

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

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