C11 atomic_load/store 和 volatile 限定词

C11 atomic_load/store and volatile qualifier

为什么C11 atomic_load/atomic_store函数中的参数有volatile限定符?众所周知,volatile 对于并发用例是无用的(例如 1, 2)。

atomic_load( const volatile A* obj );
void atomic_store( volatile A* obj , C desired);

首先,你的假设是错误的,volatile不是没用,只是不够,这是另一回事。

您引用的接口 必须 具有 volatile 资格,否则它们将无法用于如此合格的对象。

现在 volatile 对于 C11 来说是一个困难的课题,因为目前存在争论它是否仅在对象本身是 volatile 限定的情况下才有效,或者仅在访问它的当前类型时才有效。但可以肯定的是,此处 _Atomic 对象的规则与其他对象的规则没有太大区别。因此,如果您有一个非 volatile 访问且未进行修改,则编译器可以优化该访问并依赖于先前已知的值。

您可以对 _Atomic 执行的唯一此类操作是对其求值:

_Atomic size_t counter = ATOMIC_VAR_INIT(0);

++counter;         // safe: sequential consistency
...
printf("counter: %zu\n", counter); // may use some previous value
...
printf("counter: %zu\n", atomic_load(&counter)); // should use actual value

这里的"should"是因为我上面提到的volatile的不同解释。如果你想确保没有发生负载优化,你也应该始终声明你的 _Atomic 对象 volatile。它不会造成太大伤害,但在某些极端情况下可能会有所帮助。

语义原子操作意味着有多个并发线程访问变量值。这就是 volatile 说明符的用途。

您提供的两个参考资料都非常有问题并且不普遍适用(在 SW 工程中通常如此)。如果你有数据,在软件里可以同时accessed/modified,那必须是volatile.

有一些用例,其中 volatile 是绝对必要的:内核驱动程序。您不能让编译器优化对映射到设备的内存区域的访问。

有很多基于volatile的编程范式。例如,普通关键 sections/mutexes 使用 volatile 变量进行快速锁定,仅当快速锁定失败时才回退到 signals/events/etc。