【问题标题】:Can I apply the C11 `_Atomic` keyword to enum types?我可以将 C11 `_Atomic` 关键字应用于枚举类型吗?
【发布时间】:2019-03-05 19:58:08
【问题描述】:

如果我有类型

enum foo {
    FOO,
    BAR,
    BAZ,
};

然后我可以声明该类型的原子版本吗

_Atomic(enum foo);

或者我必须使用例如atomic_int 并转换 atomic_load() 的结果?

以下程序编译时没有警告:

    #include <stdatomic.h>
    #include <stdio.h>

    enum foo {FOO, BAR, BAZ};

    int main(void) {
        _Atomic(enum foo) foo_a;
        atomic_store(&foo_a, BAR);
        enum foo val = atomic_load(&foo_a);
        printf("%u\n", val);
        return 0;
    }

但确实如此:

    #include <stdatomic.h>
    #include <stdio.h>

    enum foo {FOO, BAR, BAZ};

    int main(void) {
        enum foo foo; // <---- non atomic
        atomic_store(&foo, BAR);
        enum foo val = atomic_load(&foo);
        printf("%u\n", val);
        return 0;
    }

【问题讨论】:

  • 根据port70.net/~nsz/c/c11/n1570.html#6.7.2.4p3_Atomicenum 一起使用没有任何预防措施。
  • 旁注:如果您所做的只是atomic_storeatomic_load,您可以只声明_Atomic(enum foo) foo_a;,然后使用正常的读取/分配; IIRC,_Atomic 合格类型自动执行顺序一致的读/写(匹配普通的atomic_load/atomic_store,它们也是顺序一致的)。如果声明 _Atomicfoo = BAR;enum foo val = foo; 仍将是原子操作。我对此不是 100% 确定(inc/dec/compound 分配都绝对是顺序一致的;可能不太严格的语义用于普通读/写)。
  • @ShadowRanger: AFAIK,你总是需要使用atomic_store_explicit(..., memory_order_release) 任何时候你想要比 seq_cst 弱的排序。没有办法让++= 默认为acq/rel 或relaxed 而不是seq_cst。
  • @PeterCordes:是的,我就是这么想的。在第一次检查时没有发现对普通加载和存储的保证,仅适用于读取-修改-写入操作,但即使对于最简单的操作,如果他们谨慎行事,我也不会感到惊讶。
  • @ShadowRanger:gcc / clang 可能只是在不需要时选择了该行为;我没有检查标准。

标签: c enums c11 stdatomic


【解决方案1】:

是的,所有数据类型都可以是原子的,不需要对这些使用原子通用函数。对这样一个对象的所有操作都是原子的。

对于您的第二个示例,您的编译器没有发出警告很奇怪。将非原子操作用于原子操作是违反约束的,因此编译器应该为您提供诊断。

【讨论】:

  • 对第二个例子的猜测,他们正在编译的机器并没有对非_Atomic 类型尚未满足的_Atomic 类型提出任何特殊要求(大小没有改变,对齐已经正确),编译器只是懒惰并忽略了规范违规。
  • 参数应该是 _Atomic 是有道理的,但在 C17 7.17.7.1 中它显示的格式为 void atomic_store(volatile A *object, C desired);。为什么这些参数没有_Atomic 限定?你说的违反约束到底在哪里?
  • @Lundin AFAIR 在这个子句中A 总是指原子类型。
  • 好的,但我仍然不明白将pointer-to-type 传递给期望qualified-pointer-to-type 的函数是如何违反约束的。 atomic_type 类型似乎不是不同的类型,而是 _Atomic type 的类型定义。
  • 因为_Atomic 看起来只是一个限定符,实际上并不是一个。规则是短语“qualified or unqualified type”,没有特别提到 atomic,不包括 atomic 类型。 所以指向有和没有 atomic 限定的类型的指针是不兼容的。
【解决方案2】:

是的,这是合法的。顺便说一句,您实际上并不需要括号,_Atomic enum foo foo; 是等效的。

_Atomic 与其他类型限定符一样工作,例如 constvolatile


enum foo foo;
atomic_store(&foo, BAR);

是 clang 的错误error: address argument to atomic operation must be a pointer to _Atomic type ('enum foo *' invalid)。 (来自the Godbolt compiler explorer)。


这只是 GCC 实现的一个怪癖,即使在 -Wall 处,它也可以在没有警告的情况下编译。那可能应该改变......

GCC's atomic builtinsvoid __atomic_store_n (type *ptr, type val, int memorder) 类似,采用指向普通类型的指针,而不需要 _Atomic

C++11 &lt;atomic&gt; 使用这些内置函数。同样,GCC 的 C11 stdatomic.h 使用

#define atomic_store_explicit(PTR, VAL, MO)                             \
  __extension__                                                         \
  ({                                                                    \
    __auto_type __atomic_store_ptr = (PTR);                             \
    __typeof__ (*__atomic_store_ptr) __atomic_store_tmp = (VAL);        \
    __atomic_store (__atomic_store_ptr, &__atomic_store_tmp, (MO));     \
  })

#define atomic_store(PTR, VAL)                          \
  atomic_store_explicit (PTR, VAL, __ATOMIC_SEQ_CST)

__extension__ 用于 GNU C 语句表达式,其中 x = {foo; bar;} 采用 bar 的值。)

所以这些实际上都不需要指针类型具有_Atomic

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-12
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    相关资源
    最近更新 更多