Почему летучий определитель используется через std:: atomic?
Из того, что я читал из Herb Sutter и others вы считаете, что volatile
и параллельное программирование были полностью ортогональными понятиями, по крайней мере, до C/С++.
Однако в GCC реализация все функции-члены std::atomic
имеют квалификатор volatile
. То же самое верно в Anthony Williams реализация std::atomic
.
Итак, что делать, нужны ли переменные atomic<>
volatile
или нет?
Ответы
Ответ 1
Почему спецификатор volatile
используется во всем std::atomic
?
Таким образом, изменчивые объекты также могут быть атомарными. См. здесь:
Соответствующая цитата
Функции и операции определены для работы с изменчивыми объектами, так что переменные, которые должны быть летучими, также могут быть атомарными. Однако волатильный классификатор не требуется для атомарности.
Должны ли мои переменные atomic<>
быть volatile
или нет?
Нет, атомные объекты не обязательно должны быть неустойчивыми.
Ответ 2
Подводя итог тому, что другие правильно написали:
C/С++ volatile
предназначен для аппаратного доступа и прерываний. С++ 11 atomic<>
предназначен для обмена данными между потоками (например, в незашифрованном коде). Эти два понятия/использования ортогональны, но они имеют перекрывающиеся требования, и именно поэтому люди часто путают эти два.
Причина, по которой atomic<>
имеет волютильно-квалифицированные функции, является той же самой причиной, когда у нее есть функции с константой, поскольку в принципе для объекта возможно как atomic<>
, так и const
и/или volatile
.
Конечно, как указывала моя статья, еще одним источником путаницы является то, что C/С++ volatile
не совпадает с С#/Java volatile
(последний в основном эквивалентен С++ 11 atomic<>
).
Ответ 3
Как const, летучесть является транзитивной. Если вы объявите метод как volatile
, то вы не можете вызвать какой-либо нелетучий метод на нем или на любой из его атрибутов-членов. Имея std::atomic
методы volatile
, вы разрешаете вызовы из методов-членов volatile
в классах, содержащих переменные std::atomic
.
У меня нет хорошего дня... так запутанно... может быть, небольшой пример помогает:
struct element {
void op1() volatile;
void op2();
};
struct container {
void foo() volatile {
e.op1(); // correct
//e.op2(); // compile time error
}
element e;
};