Интересно, вы неправильно поняли, что означает volatile
. Volatile можно использовать с типами, которые можно читать или записывать как атомарное действие.
Нет захвата / выпуска блокировки , только барьер для перекомпоновки во время компиляции и во время выполнения для обеспечения семантики aquire / release без блокировки (https://preshing.com/20120913/acquire-and-release-semantics/). На не x86 это может потребовать указания барьера в ассемблере, но не взломать замок.
volatile
указывает, что поле может быть изменено другими потоками, поэтому чтение / запись должны рассматриваться как элементарные, а не оптимизированные.
Ваш вопрос немного двусмысленный.
1 / Если вы имеете в виду, преобразует ли компилятор:
var local = something;
if (local != null) local.DoThings();
в
if (something != null) something.DoThings();
тогда ответ - нет.
2 / Если вы имеете в виду, будет ли дважды вызываться «DoThings()
» для одного и того же объекта:
var local = something;
if (local != null) local.DoThings();
if (something != null) something.DoThings();
тогда ответ в основном да, если только другой поток не изменил значение "something
" до вызова второго "DoThings()
". Если это так, то это может привести к ошибке времени выполнения - если после оценки условия «if
» и до вызова «DoThings
» другой поток устанавливает для «something
» значение null
, то вы получит ошибку во время выполнения. Я предполагаю, что именно поэтому у вас есть "var local = something;
".
3 / Если вы имеете в виду, будет ли следующее чтение двух:
if (something != null) something.DoThings();
тогда да, одно чтение условия и второе чтение, когда оно вызывает DoThings()
(при условии, что something
не равно нулю). Если бы он не был помечен volatile
, компилятор мог бы справиться с этим за одно чтение.
В любом случае реализация функции "DoThings()
" должна знать, что она может вызываться несколькими потоками, поэтому необходимо рассмотреть возможность включения комбинации блокировок и ее собственных изменяемых членов.