То, что вы знаете, ложно. Volatile не используется для синхронизации доступа к памяти между потоками, применения каких-либо ограждений памяти или чего-либо подобного. Операции с volatile
памятью не являются атомарными, и их порядок не гарантируется. volatile
- одно из самых непонятых средств во всем языке. "Неустойчивый практически бесполезен для многопоточного программирования. "
volatile
используется для взаимодействия с отображаемым в память оборудованием, обработчиками сигналов и инструкцией машинного кода setjmp
.
Его также можно использовать аналогично const
, и именно так Александреску использует его в этой статье. Но не ошибитесь. volatile
не делает ваш код волшебным образом потокобезопасным. При использовании именно таким образом это просто инструмент, который может помочь компилятору сказать вам, где вы могли напортачить. Вы все еще должны исправить свои ошибки, и volatile
не играет никакой роли в исправлении этих ошибок.
РЕДАКТИРОВАТЬ: Я постараюсь немного уточнить то, что я только что сказал.
Предположим, у вас есть класс, у которого есть указатель на что-то, что не может изменить. Естественно, вы можете сделать указатель const:
class MyGizmo
{
public:
const Foo* foo_;
};
Что на самом деле const
делает для вас здесь? Это ничего не делает с памятью. Это не похоже на язычок защиты от записи на старых дискетах. Сама память все еще доступна для записи. Просто нельзя писать в него через указатель foo_
. Итак, const
- это просто способ дать компилятору еще один способ сообщить вам, когда вы можете ошибиться. Если бы вы написали этот код:
gizmo.foo_->bar_ = 42;
... компилятор этого не допустит, потому что он помечен как const
. Очевидно, вы можете обойти это, используя const_cast
, чтобы отбросить const
-ность, но если вам нужно убедиться, что это плохая идея, тогда вам не поможет. :)
Александреску использует volatile
точно так же. Он не делает ничего, чтобы сделать память «потокобезопасной» каким-либо образом. Что он делает, так это дает компилятору еще один способ сообщить вам, когда вы, возможно, облажались. Вы помечаете вещи, которые вы сделали действительно «потокобезопасными» (за счет использования реальных объектов синхронизации, таких как мьютексы или семафоры), как volatile
. Тогда компилятор не позволит вам использовать их в контексте, отличном от volatile
. Это вызывает ошибку компилятора, о которой вам нужно подумать и исправить. Вы можете снова обойти это, отбросив volatile
-ность, используя const_cast
, но это так же зло, как отбросить const
.
Мой вам совет - полностью отказаться от volatile
как инструмента для написания многопоточных приложений (редактировать :), пока вы не действительно поймете, что делаете и почему. Он имеет некоторые преимущества, но не так, как думает большинство людей, и если вы воспользуетесь им неправильно, вы можете написать опасно небезопасные приложения.
person
John Dibling
schedule
09.11.2010
volatile
не может использоваться в качестве синхронизации потоков для бедняков (хотя компиляторы могут таким образом расширить его значение). Запись в объектvolatile
в одном потоке не обязательно означает, что другой поток увидит обновленное значение. (Он мог быть записан только в кэш одного ЦП, но не через кеш в ту память, которую разделяют ЦП.) Для этого вам нужны барьеры памяти. - person sbi   schedule 09.11.2010volatile
: записи должны быть в основной памяти. Причина, по которой его нельзя использовать для синхронизации, заключается в том, что гарантии не гарантируют атомарность или переупорядочение с использованием энергонезависимых переменных. - person David Rodríguez - dribeas   schedule 09.11.2010volatile
записи в основную память. - person zwol   schedule 09.11.2010volatile
часто используется для адресов, которые даже не соответствуют памяти, поэтому я думаю, что это должно быть неправильно. Но да, я забыл о проблемах атомарности и порядка записи. - person sbi   schedule 09.11.2010