Должна ли переменная блокировки быть измененной?
У меня есть следующая инструкция Lock:
private readonly object ownerLock_ = new object();
lock (ownerLock_)
{
}
Должен ли я использовать volatile ключевое слово для моей переменной блокировки?
private readonly volatile object ownerLock_ = new object();
В MSDN я видел, что он обычно используется для поля, к которому обращаются без блокировки, поэтому, если я использую Lock, мне не нужно использовать volatile?
От MSDN:
Модификатор volatile обычно используется для поля, к которому осуществляется доступ несколько потоков без использования оператора блокировки для сериализации доступа.
Ответы
Ответ 1
Если вы только когда-либо обращаетесь к данным, которые блокируют "охранники", когда вы владеете блокировкой, тогда да - сделать эти поля неустойчивыми излишними. Вам не нужно также изменять переменную ownerLock_
. (В настоящий момент в операторе lock
вы не указали какой-либо фактический код, что затрудняет разговор в конкретных терминах - но я предполагаю, что вы действительно будете читать/изменять некоторые данные в инструкции lock
. )
volatile
должен использоваться очень редко в коде приложения. Если вам нужен свободный доступ к одной переменной, Interlocked
почти всегда проще рассуждать. Если вам нужен свободный доступ, я почти всегда начинаю блокировку. (Или попробуйте использовать неизменяемые структуры данных для начала.)
Я бы только ожидал увидеть volatile
внутри кода, который пытается создать абстракции более высокого уровня для потоковой передачи - например, в базе кода TPL. Это действительно инструмент для экспертов, которые действительно хорошо понимают модель памяти .NET... из которых их очень мало, ИМО.
Ответ 2
Если что-то есть readonly
, это поточно-безопасное, период. (Ну, почти. Эксперт может выяснить, как получить исключение NullReferenceException в вашем lock
, но это будет непросто.) С readonly
вам не нужны volatile
, Interlocked
, или блокировки. Это идеальное ключевое слово для многопоточности, и вы должны использовать его там, где сможете. Он отлично работает для объекта блокировки, где его большой недостаток (вы не можете изменить значение) не имеет значения.
Кроме того, в то время как ссылка является неизменной, ссылка на объект не может быть. "new object()" здесь, но если это был List
или что-то другое, изменяемое, а не потокобезопасное, вы хотели бы заблокировать ссылку (и все другие ссылки на нее, если таковые имеются), чтобы сохранить объект меняется одновременно на два потока.