Casting pointers to _Atomic pointers and _Atomic sizes

为君一笑 提交于 2020-01-03 15:39:10

问题


By my reading of the standard, *(_Atomic TYPE*)&(TYPE){0} (in words, casting a pointer to a non-atomic to a pointer to a corresponding atomic and dereferencing) isn't supported.

Do gcc and/or clang recognize it as an extension if TYPE is/isn't lock-free? (Question 1)

Second and related question: I was under the impression that if TYPE couldn't be implemented as a lock free atomic, a lock would need to be embedded in the corresponding _Atomic TYPE. But if I make TYPE a largish struct, then on both clang and gcc it has the same size as _Atomic TYPE.

Code for both problems:

#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));
}

Now, if I compile the above snippet with -DSTRUCT, both gcc and clang keep the both the struct and its atomic variant at the same size, and they generate a call to a function named __atomic_store for the store (resolved by linking with -latomic).

How does this work if no lock is embedded in the _Atomic version of the struct? (Question 2)


回答1:


_Atomic changes alignment in some corner cases on Clang, and GCC will likely be fixed in the future as well (PR 65146). In these cases, adding _Atomic through a cast does not work (which is fine from a C standard point of view because it is undefined behavior, as you pointed out).

If the alignment is correct, it is more appropriate to use the __atomic builtins, which have been designed for exactly this use case:

  • Built-in Functions for Memory Model Aware Atomic Operations

As described above, this will not work in cases where the ABI provides insufficient alignment for plain (non-atomic) types, and where _Atomic would change alignment (with Clang only for now).

These builtins also work in case of non-atomic types because they use out-of-line locks. This is also the reason why no additional storage is required for _Atomic types, which use the same mechanism. This means that there is some unnecessary contention due to unintentional sharing of the locks. How these locks are implemented is an implementation detail which could change in future versions of libatomic.

In general, for types with atomic builtins that involve locking, using them with shared or aliased memory mappings does not work. These builtins are not async-signal-safe, either. (All these features are technically outside the C standard anyway.)



来源:https://stackoverflow.com/questions/55299525/casting-pointers-to-atomic-pointers-and-atomic-sizes

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!