V2643. MISRA. All memory synchronization operation should be executed in sequentially consistent order.
Данное диагностическое правило основано на руководстве MISRA (Motor Industry Software Reliability Association) по разработке программного обеспечения.
Это правило актуально только для языка C.
При использовании функций для работы с атомарными операциями аргумент, отвечающий за тип модели памяти, должен всегда иметь значение memory_order::memory_order_seq_cst
(последовательная согласованность).
При использовании в многопоточном коде атомарных операций может сложиться ситуация, когда один поток обратится к значению переменной раньше, чем другой поток это значение изменит. Для синхронизации операций чтения/записи в языке C существуют модели памяти, определённые в перечислении memory_order
.
Выбранная модель памяти влияет на то, как компилятор и процессор оптимизируют код. Поведением по умолчанию является sequentially consistent ordering (последовательная согласованность). Эта модель поведения наиболее интуитивно понятна для человека. А также это самая строгая модель для компилятора и процессора. При её использовании операции чтения/записи будут выполняться чётко в том порядке, в котором они написаны в коде.
Данное диагностическое правило призвано уменьшить вероятность ошибки и исключить зависимость выполнения параллельного кода от оптимизаций процессора и компилятора.
Ниже перечислены функции из Concurrency support library, которые должны вызываться со значением 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
.
Пример некорректного кода:
_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
не может быть заранее предсказан, поскольку нестрогая модель памяти позволит компилятору и процессору менять очередность операций.
Корректный код:
_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);
}
}
Данная диагностика классифицируется как:
|