C原子操作,如果写入都是原子交换,我需要原子加载吗?

时间:2013-02-23 06:00:50

标签: c multithreading atomic thread-synchronization compare-and-swap

我正在用C语言编写一个程序。简单地说:有许多线程可以读写的变量。每次写入其中一个时,它都是通过原子交换(GCC原子操作,同步和交换)编写的。每次读取其中一个变量时,是否需要使用原子加载,或者原子写入是否足以避免在写入中读取数据?

注意,任何需要使用其中一个变量的数据的人都会首先复制值:

int success = 0;
while ( !success ) {
  int x = shared_x;
  ... work with x, result in y ...
  success = cmp_swap( &shared_x, x, y );
}

我的问题不是关于数据竞争,我不担心我可能会丢失数据。我担心的是,在阅读它之后,shared_x的价值可能会发生变化。假设它是一个8字节的整数,这是一个潜在的问题:比如说shared_x是一个64位整数,8个字节。我的x = shared_x是否可能复制前4个字节,然后原子地写入shared_x,然后此语句完成读取后4个字节。这将导致x包含旧值shared_x的前4个字节,以及新shared_x的最后4个字节。我怀疑原子交换中的内存障碍(http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Atomic-Builtins.html - 使用__sync_bool_compare_and_swap)足以防止这种情况......但我不确定。

1 个答案:

答案 0 :(得分:3)

看起来您正在阅读shared_x,计算新内容,然后回写shared_x。您写入shared_x的值似乎取决于您最初从中读取的值。

如果是这种情况,那么你就有了一个依赖关系,并且很可能不仅需要使读取原子,而且需要使“读取,计算,回写”的整个操作成为原子。意思是,您需要同步它。就像互斥体一样。

我说“最有可能”,因为我无法确定我是否不知道代码实际上做了什么。您需要分析在竞争情况下发生的情况,其中线程A写入shared_x,而线程B当前正在基于旧值shared_x进行计算,然后将结果写回给它。线程A写入它的值永远丢失。我不知道这对你来说是否有问题。只有你能知道。如果该竞争条件正常,则您不需要同步或使读取原子。

如果您只想确保从shared_x读取不会让您感到垃圾并且不关心上述竞争条件,那么答案是“很可能您不需要让阅读原子。“而不是我复制和粘贴,你可以在这里阅读详细信息:

Atomicity in C++ : Myth or Reality

即使问题是针对C ++,C也是如此。

请注意,虽然原子现在也在C标准中(C11),由<stdatomic.h>标头和_Atomic类型限定符提供。但当然并非所有编译器都支持C11。