我可以不使用atomic_load读取原子变量吗?

Cor*_*lks 5 c multithreading c11

我有一个单作者,多读者的情况。一个线程正在写入一个计数器,任何线程都可以读取该计数器。由于单个写入线程不必担心与其他线程竞争数据访问权限,因此以下代码安全吗?

#include <stdatomic.h>
#include <stdint.h>

_Atomic uint32_t counter;

// Only 1 thread calls this function. No other thread is allowed to.
uint32_t increment_counter() {
    atomic_fetch_add_explicit(&counter, 1, memory_order_relaxed);
    return counter;  // This is the line in question.
}

// Any thread may call this function.
uint32_t load_counter() {
    return atomic_load_explicit(&counter, memory_order_relaxed);
}
Run Code Online (Sandbox Code Playgroud)

writer线程只读取counter直接的内容,而无需调用任何atomic_load*函数。这应该是安全的(因为多个线程读取一个值是安全的),但是我不知道声明变量是否会_Atomic限制您直接使用该变量,或者是否需要始终使用其中一个atomic_load*函数读取它。

Jen*_*edt 6

是的,您对对象执行的所有操作_Atomic都保证有效,就像您发出具有顺序一致性的相应调用一样。在您的特定情况下,评估相当于atomic_load.

但是那里使用的算法是错误的,因为通过执行atomic_fetch_add和评估,返回的值可能已经被另一个线程更改。正确的是

uint32_t ret = atomic_fetch_add_explicit(&counter, 1, memory_order_relaxed);
return ret+1;
Run Code Online (Sandbox Code Playgroud)

这看起来有点次优,因为加法完成了两次,但一个好的优化器会解决这个问题。

  • 啊,我想我可能找到了相关的引用。“具有原子类型的对象的加载和存储是通过‘memory_order_seq_cst’语义完成的。” (第 6.2.6.1 节第 9 段)看看标准,你是对的;它有点分散(例如,后递增/递减讨论 6.5.2.4/2 中的原子)。感谢您澄清这一点! (2认同)