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

Диагностическое правило основано на руководстве [MISRA](https://misra.org.uk/) \(Motor Industry Software Reliability Association\) по разработке программного обеспечения\.

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

Прямой доступ \(оператор `.` или `->`\) к полям структур или объединений объектов атомарных типов может привести к [гонке данных](https://pvs-studio.ru/ru/blog/terms/0042/)\. Вместо этого доступ к объекту следует осуществлять с использованием специальных функций из `<stdatomic.h>` и оператора присваивания `=`\.

[Стандарт C](https://en.cppreference.com/w/c/header/stdatomic.html) определяет следующие функции для доступа к атомарным объектам:

1. `atomic_init`
1. `atomic_store`
1. `atomic_load`
1. `atomic_exchange`
1. `atomic_compare_exchange`

[Стандарт гарантирует](https://en.cppreference.com/w/c/language/atomic.html), что выполнение атомарных операций с данными, которые используются в нескольких потоках, не приведёт к гонке данных\. Однако прямой доступ к полям объектов атомарных типов нарушает эту гарантию\.

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

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

```cpp
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 предлагает исправлять подобный код следующим образом:

```cpp
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;
}
```

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

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

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

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