通过我阅读标准,*(_Atomic TYPE*)&(TYPE){0}
(用文字表示,将指向非原子的指针转换为指向相应原子和解除引用的指针)不受支持。
如果TYPE
不是无锁,那么gcc和/或clang是否将其识别为扩展名? (问题1)
第二个相关问题:我的印象是,如果TYPE
无法实现为无锁原子,则需要将锁定嵌入相应的_Atomic TYPE
中。但是,如果我让TYPE
成为一个较大的结构,那么在clang
和gcc
它的大小与_Atomic TYPE
相同。
两个问题的代码:
#include <stdatomic.h>
#include <stdio.h>
#if STRUCT
typedef struct {
int x;
char bytes[50];
} TYPE;
#else
typedef int TYPE;
#endif
TYPE x;
void f (_Atomic TYPE *X)
{
*X = (TYPE){0};
}
void use_f()
{
f((_Atomic TYPE*)(&x));
}
#include <stdio.h>
int main()
{
printf("%zu %zu\n", sizeof(TYPE), sizeof(_Atomic TYPE));
}
现在,如果我用-DSTRUCT
编译上面的代码片段,gcc和clang都会保持struct和它的原子变体的大小相同,并且它们会为商店生成一个名为__atomic_store
的函数的调用(通过与-latomic
链接来解析)。
如果在_Atomic
版本的结构中没有嵌入锁,这是如何工作的? (问题2)
_Atomic
在Clang的某些角落情况下改变了对齐方式,GCC也可能在将来修复(PR 65146)。在这些情况下,通过强制转换添加_Atomic
不起作用(从C标准的角度来看这很好,因为它是未定义的行为,正如您所指出的那样)。
如果对齐是正确的,那么使用__atomic
builtins更合适,它就是针对这个用例而设计的:
如上所述,这在ABI为普通(非原子)类型提供不充分对齐的情况下不起作用,并且_Atomic
将改变对齐的情况(目前仅与Clang一起)。
这些内置函数也适用于非原子类型,因为它们使用外部锁。这也是使用相同机制的_Atomic
类型不需要额外存储的原因。这意味着由于无意中共享锁而存在一些不必要的争用。如何实现这些锁是一个实现细节,可能会在未来版本的libatomic
中发生变化。
通常,对于具有涉及锁定的原子内置类型的类型,将它们与共享或别名内存映射一起使用不起作用。这些内置也不是异步信号安全的。 (无论如何,所有这些功能在技术上都超出了C标准。)