Из того, что я читал от Herb Sutter и других, Вы думали бы это volatile
и параллельное программирование было абсолютно ортогональными понятиями, по крайней мере, что касается C/C++.
Однако в реализации GCC весь из std::atomic
функции членства имеют volatile
спецификатор. То же верно в реализации Anthony Williams std::atomic
.
Таким образом, что такое соглашение, мой atomic<>
переменные должны быть volatile
или нет?
Почему квалификатор volatile
используется в std::atomic
?
Чтобы волатильные объекты также могли быть атомарными. См. здесь:
Соответствующая цитата:
Функции и операции определены для работы с изменчивыми объектами, так что переменные, которые должны быть изменчивыми, также могут быть атомарными. Квалификатор volatile, однако, не требуется для атомарности.
Должны ли мои атомарные<>
переменные быть волатильными
или нет?
Нет, атомарные объекты не обязательно должны быть волатильными.
Подводя итог тому, что правильно написали другие:
C/C++ volatile
- для аппаратного доступа и прерываний. В C++11 atomic<>
- для межпоточной коммуникации (например, в lock-free коде). Эти два понятия/использования ортогональны, но их требования пересекаются, и именно поэтому люди часто путают их.
Причина, по которой atomic<>
имеет volatile-qualified функции, та же, по которой он имеет const-qualified функции, потому что в принципе возможно, чтобы объект был одновременно atomic<>
, а также const
и/или volatile
.
Конечно, как указывалось в моей статье, еще одним источником путаницы является то, что volatile
в C/C++ не то же самое, что volatile
в C#/Java (последнее в основном эквивалентно atomic<>
в C++11).
Как и const, volatile является транзитивным. Если вы объявляете метод как 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;
};