Приведение указателей к _Атомным указателям и _Атомным размерам - PullRequest
5 голосов
/ 22 марта 2019

По моему прочтению стандарта, *(_Atomic TYPE*)&(TYPE){0} (на словах приведение указателя на неатомарный указатель на соответствующий атомарный элемент и разыменование) не поддерживается.

gcc и / или clang распознают его как расширение, если TYPE не заблокирован? (Вопрос 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 сохранят как структуру, так и ее атомарный вариант одинакового размера, и сгенерируют вызов функции с именем __atomic_store для хранилища ( разрешается связыванием с -latomic).

Как это работает, если в версии _Atomic структуры нет встроенной блокировки? (Вопрос 2)

1 Ответ

4 голосов
/ 22 марта 2019

_Atomic меняет выравнивание в некоторых угловых случаях на Clang, и GCC, скорее всего, будет исправлено и в будущем ( PR 65146 ).В этих случаях добавление _Atomic через приведение не работает (что нормально со стандартной точки зрения C, поскольку, как вы указали, это неопределенное поведение).

Если выравнивание правильное, оноболее целесообразно использовать встроенные функции __atomic, которые были разработаны именно для этого случая использования:

Как описано выше, это не будет работать в случаях, когда ABI обеспечивает недостаточное выравнивание для простых (неатомарных) типов, и когда _Atomic изменит выравнивание (пока только с Clang).

Эти встроенные функции также работают в случае неатомарных типов, потому что они используют внеплановые блокировки.Это также причина, по которой дополнительное хранилище не требуется для типов _Atomic, которые используют тот же механизм.Это означает, что существует некоторая ненужная конкуренция из-за непреднамеренного совместного использования замков.Реализация этих блокировок - это деталь реализации, которая может измениться в будущих версиях libatomic.

В целом, для типов с атомарными встроенными функциями, которые включают блокировку, использование их с отображениями совместно используемой или псевдонимной памяти не работает.Эти встроенные функции также не безопасны для асинхронных сигналов.(В любом случае, все эти функции технически не соответствуют стандарту C.)

...