Разрешает ли модель памяти C / C ++ атомизацию с разной гранулярностью для одних и тех же байтов? - PullRequest
1 голос
/ 24 марта 2020

Предположим, у меня есть следующий тип:

struct T {
  int32 high;
  int32 low;
};

Определено ли поведение для выполнения доступа атомом c (с использованием, например, atomic_load, atomic_fetch_add) для всех x, &x->high и &x->low (при условии U* x)?

Насколько я понимаю, модели памяти C / C ++ определяются с использованием историй по отдельным местоположениям (для размещения слабых архитектур памяти). Если доступы могут пересекать местоположения, означает ли это синхронизацию между местоположениями? Если это так, то я предполагаю, что это будет означать, что истории, по сути, являются байтами, а доступ к int аналогичен синхронизации между основными 4 (или 8) байтами.

edit : исправлен пример, чтобы избежать объединения, так как основная часть вопроса касается модели параллелизма.

edit : исправлено использование стандартной атомики из stdatomic.h

Ответы [ 2 ]

2 голосов
/ 24 марта 2020

Для C11 / C18 (я не могу говорить о C ++) функции Standard atomic_xxx() из <stdatomic.h> определены только для получения _Atomic квалифицированных аргументов. Поэтому для выполнения atomic_xxx() операций над полями вашего struct T вам потребуется:

struct T {
  _Atomic int32 high;
  _Atomic int32 low;
} ;

struct T foo, bar ;

и тогда вы сможете (например) atomic_fetch_add(&foo->high, 42). Но bar = atomic_load(&foo) будет неопределенным.

И наоборот, вы можете иметь:

struct T {
  int32 high;
  int32 low;
} ;

_Atomic struct T foo ;
        struct T bar ;

, и теперь bar = atomic_load(&foo) определено. Но доступ к любому отдельному полю в foo не определен - независимо от того, является ли он _Atomic.

Исходя из Стандарта, объекты _Atomic xxxx следует рассматривать как совершенно отличные от «обычных» xxxx объекты - они могут иметь разные размеры, представления и выравнивания. Поэтому приведение xxxx к / от _Atomic xxxx не более разумно, чем приведение одного struct к / от другого, отличающегося struct.

Но , для g cc и встроенные __atomic_xxx(), вы можете делать все, что поддерживает процессор. Действительно, для g cc (иначе) стандартный atomic_xxx() будет принимать аргументы, которые являются не _Atomic квалифицированными типами и отображаются на встроенные модули. clang, с другой стороны, рассматривает передачу квалифицированного типа , а не _Atomic стандартным функциям как ошибку. ИМХО это ошибка в g cc s <stdatomic.h>.

0 голосов
/ 24 марта 2020

Загрузка неактивного члена объединения дает неопределенное значение независимо от того, используется или не используется __atomic_load для этой загрузки.

...