# V2647. MISRA. Structure and union members of atomic objects should not be directly accessed.

Диагностическое правило основано на руководстве MISRA (Motor Industry Software Reliability Association) по разработке программного обеспечения.

Это правило актуально только для языка C.

Прямой доступ (оператор `.` или `->`) к полям структур или объединений объектов атомарных типов может привести к гонке данных. Вместо этого доступ к объекту следует осуществлять с использованием специальных функций из `<stdatomic.h>` и оператора присваивания `=`.

Стандарт C определяет следующие функции для доступа к атомарным объектам:

- `atomic_init`
- `atomic_store`
- `atomic_load`
- `atomic_exchange`
- `atomic_compare_exchange`

Стандарт гарантирует, что выполнение атомарных операций с данными, которые используются в нескольких потоках, не приведёт к гонке данных. Однако прямой доступ к полям объектов атомарных типов нарушает эту гарантию.

Примечание. Функция `atomic_init` сама по себе не предотвращает потенциально возможную гонку данных. Если несколько потоков в момент инициализации обращаются к переменной, даже используя атомарные операции, это всё равно может привести к состоянию гонки.

Пример некорректного кода:

    typedef struct {
      int32_t width;
      int32_t height;
    } rectangle_t;

    _Atomic rectangle_t rect;

    int foo(void)
    {
      rect.width = 300;

      return 0;
    }

В примере прямая запись `rect.width = 300;` может привести к гонкам данных и невалидному состоянию объекта.

Руководство MISRA предлагает исправлять подобный код следующим образом:

    typedef struct {
      int32_t width;
      int32_t height;
    } rectangle_t;

    _Atomic rectangle_t rect;

    int foo(void)
    {
      rectangle_t tmp;

      tmp = atomic_load(&rect);

      tmp.height = 400;

      atomic_store(&rect, tmp);

      return 0;
    }

Однако такое исправление нельзя считать самодостаточным. Исчезла проблема неатомарного изменения полей в структуре, но добавилась новая потенциальная проблема синхронизации.

Рассмотрим следующий сценарий:

- Первый поток вызвал функцию `foo` и скопировал структуру в переменную `tmp`.
- Пока первый поток меняет значение `tmp.height`, второй поток может поменять значение `rect.width`.
- Первый поток вызывает функцию `atomic_store`, перезаписывает `rect.width` старым значением. Ошибка.

Чтобы избежать такой проблемы, может потребоваться дополнительная синхронизация между разными потоками. Однако данная тема выходит за рамки диагностического правила MISRA.

Данная диагностика классифицируется как:

MISRA-C-2023-12.6