﻿# V2643\. MISRA\. All memory synchronization operation should be executed in sequentially consistent order\.

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

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

При использовании функций для работы с атомарными операциями аргумент, отвечающий за тип модели памяти, должен всегда иметь значение `memory_order::memory_order_seq_cst` \(последовательная согласованность\)\.

При использовании в многопоточном коде атомарных операций может сложиться ситуация, когда один поток обратится к значению переменной раньше, чем другой поток это значение изменит\. Для синхронизации операций чтения/записи в языке C существуют модели памяти, определённые в перечислении [`memory_order`](https://en.cppreference.com/w/c/atomic/memory_order)\.

Выбранная модель памяти влияет на то, как компилятор и процессор оптимизируют код\. Поведением по умолчанию является [sequentially consistent ordering](https://en.cppreference.com/w/c/atomic/memory_order#Sequentially-consistent_ordering) \(последовательная согласованность\)\. Эта модель поведения наиболее интуитивно понятна для человека\. А также это самая строгая модель для компилятора и процессора\. При её использовании операции чтения/записи будут выполняться чётко в том порядке, в котором они написаны в коде\.

Данное диагностическое правило призвано уменьшить вероятность ошибки и исключить зависимость выполнения параллельного кода от оптимизаций процессора и компилятора\.

Ниже перечислены функции из [Concurrency support library](https://en.cppreference.com/w/c/thread), которые должны вызываться со значением `memory_order::memory_order_seq_cst`:

* `atomic_load_explicit`,
* `atomic_store_explicit`,
* `atomic_flag_test_and_set_explicit`,
* `atomic_flag_clear_explicit`,
* `atomic_exchange_explicit`,
* `atomic_compare_exchange_strong_explicit`,
* `atomic_compare_exchange_weak_explicit`,
* `atomic_fetch_add_explicit`,
* `atomic_fetch_sub_explicit`,
* `atomic_fetch_or_explicit`,
* `atomic_fetch_xor_explicit`,
* `atomic_fetch_and_explicit`,
* `atomic_thread_fence`,
* `atomic_signal_fence`\.

Помимо явной передачи аргумента можно использовать не `*_explicit` альтернативы вышеописанных функций\. В таком случае будет неявно передан аргумент `memory_order::memory_order_seq_cst`\.

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

```cpp
_Atomic int flag; // initialized elsewhere with non-zero value

void thread1()
{
  // do stuff
  atomic_store_explicit(&flag, 0, memory_order_release);
}

void thread2()
{
  auto value = atomic_load_explicit(&flag, memory_order_acquire);
  while (value != 0)
  {
    // do stuff
    value = atomic_load_explicit(&flag, memory_order_acquire);
  }
}
```

В приведённом выше синтетическом примере порядок выполнения операций `load` и `store` не может быть заранее предсказан, поскольку нестрогая модель памяти позволит компилятору и процессору менять очередность операций\.

Корректный код:

```cpp
_Atomic int flag; // initialized elsewhere with non-zero value

void thread1()
{
  // do some stuff

  atomic_store_explicit(&flag, 0, memory_order_seq_cst);
  // or use atomic_store(&flag, 0);
}

void thread2()
{
  auto value = atomic_load_explicit(&flag, memory_order_seq_cst);

  // or declaration via 'atomic_load'
  // auto value = atomic_load(&flag);

  while (value != 0)
  {
    // do some stuff

    value = atomic_load_explicit(&flag, memory_order_seq_cst);
    // or assignment via 'atomic_load'
    // value = atomic_load(&flag);
  }
}
```