Единственный атомарный тип, для которого гарантируется свойство lock-free — это std::atomic_flag
. Все специализации std::atomic<T>
могут использовать мьютексы для опеспечения атомарности операций.
Подробное описание Ссылка на заголовок
std::atomic_flag
(не путать с std::atomic<bool>
) — единственный атомарный тип, для которого стандарт C++ гарантирует свойство lock-free:
Операции над объектом
atomic_flag
должны быть lock-free.
Строгое определние lock-free операции: если несколько потоков выполняют lock-free операции, хотя бы один из потоков в конце концов завершит выполнение операции, вне зависимости от состояния других потоков. Таким образом, если владеющий lock-ом поток был прерван, все потоки, ожидающие этот lock, не смогут завершить выполнение операции. Это значит, что lock-free операции не могут использовать блокировки.
Примечание: lock-free операция всегда обладает более слабым свойством obstruction-free, но не обязательно обладает более строгим свойством wait-free. Хорошая статья о данных свойствах на 1024cores.
Гарантия lock-free предоставляется только для std::atomic_flag
. Другие атомарные типы могут не быть lock-free, и их операции могут быть реализованы с использованием внутренних блокировок (и, следовательно, могут блокироваться). Однако на практике многие специализации std::atomic<T>
будут также lock-free. Чтобы проверить, является ли данная специализация std::atomic<T>
lock-free на целевой платформе, используйте метод is_lock_free()
или static constexpr std::atomic<T>::is_always_lock_free
. Зачем нужны оба способа? Теоретически is_always_lock_free
может быть false
, в то время как для конкретного объекта is_lock_free()
вернёт true
. Иными словами, lock-free свойство не может быть гарантировано для некоторых специализаций std::atomic
, в то время как конкретные объекты могут обладать этим свойством. Так может произойти из-за требований платформы, соответствие которым может быть проверено только в ходе выполнения. Например, платформа может требовать выравнивания для атомарного объекта; неправильно выровненный атомарный объект не будет lock-free.
Почему std::atomic_flag
единственный тип с гарантией lock-free? N2427 поясняет:
Операции с
atomic_flag
должны выполняться без блокировок. Типatomic_flag
— это минимальный аппаратно реализуемый тип, необходимый для соответствия этому стандарту. Остальные типы могут быть эмулированы с помощьюatomic_flag
, хотя при этом их свойства будут далеки от оптимальных.
Пример Ссылка на заголовок
К примеру, процессор может не поддерживать атомарные операции для достаточно крупного типа T
в шаблоне std::atomic<T>
, поэтому для обеспечения атомарности реализация может прибегнуть к блокировкам:
#include <atomic>
#include <iostream>
int main() {
struct A{int x[2];};
struct B{int x[20];};
std::cout << std::atomic<A>::is_always_lock_free <<
std::atomic<B>::is_always_lock_free;
}
Возможный вывод:
10