Почему летучий определитель используется через 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;
};