2010-01-11 3 views
11

Необходимо ли защищать доступ к одной переменной ссылочного типа в многопоточном приложении? В настоящее время я блокирую эту переменную следующим образом:Необходим ли замок в этой ситуации?

private readonly object _lock = new object(); 
private MyType _value; 
public MyType Value 
{ 
    get { lock (_lock) return _value; } 
    set { lock (_lock) _value = value; } 
} 

Но мне интересно, действительно ли это необходимо? Не является ли присвоение значения атомному полю? Может ли что-то пойти не так, если я не заблокирую в этом случае?

P.S .: MyType - неизменный класс: все поля задаются в конструкторе и не меняются. Чтобы что-то изменить, создается новый экземпляр и назначается переменной выше.

+4

Предположим, я спросил вас: «Замок на двери нужен?» Вы вполне можете ответить, заметив, что я не описал дверь или задачу, которую должна выполнить дверь. Блокировка необходима на двери, если задача, которую была придумана дверью, не может быть достигнута без добавления замка. Никто не может сказать вам, может ли задача, для которой предназначена ваша переменная, без блокировки, если вы не сообщите им, что это за задача. Дайте * подробное и полное * объяснение * каждого возможного сценария потоковой передачи *, в котором может использоваться переменная, и какую семантику вы хотите выполнять в каждой. –

ответ

10

Быть атомным редко бывает достаточно.

Обычно я хочу получить последнее значение для переменной, а не потенциально видеть устаревшую, поэтому необходим какой-то барьер памяти, как для чтения, так и для записи. Блокировка - это простой способ добиться этого, ценой потенциальной потери производительности из-за конкуренции.

I использовать, чтобы полагать, что сделать переменную изменчивость будет достаточно в этой ситуации. Я больше не уверен, что это так. В основном я теперь стараюсь избегать написания кода без блокировки, когда задействованы общие данные, если только я не могу использовать блоки, написанные людьми, которые действительно понимают эти вещи (например, Джо Даффи).

+0

you r right. мой ответ неправильный. – Benny

+1

Кроме того, как вы сами говорите в http://www.yoda.arachsys.com/csharp/threads/volatility.shtml, нет даже гарантии, что присвоение является атомарным (зависит от выравнивания памяти) –

+1

@Jon, последний против устаревших "является любопытным и неопределенным. Я имею в виду, даже если он полностью заблокирован и защищен, то значение, которое вы получаете при чтении, является дезодорантом по несколько случайному поведению алгоритма процесса OS-процесса ... Он может запускать поток чтения непосредственно перед другой «параллельной» записью или наоборот ... Этот класс проблем выходит за рамки того, что мы обычно рассматриваем как проблему с несколькими потоками. Если это важно, ему нужно управлять каким-то другим механизмом ... нет? –

0

все зависит от того, будет ли доступ к ресурсу несколькими потоками. и некоторая переменная называется атомной операцией, в этом случае с атомной операцией нет необходимости использовать блокировку. извините за плохой английский.

в этом случае, непреложный, думаю блокировка не требуется.

+2

Является ли объект неизменным, не имеет значения. * Variable * является изменяемым; поэтому их называют «переменными». –

+0

-1 потому что Эрик прав. – tony

7

Для этого используется ключевое слово volatile. Безопасно ли это, не зависит от сценария. Но компилятор может сделать funny stuff, например, реорганизовать порядок работы. Поэтому даже чтение/запись в одно поле может быть небезопасным.

+0

эй, ваша ссылка на volatile неверна ... –

+0

Моя ошибка. Исправлена ​​ссылка. – ewernli

+1

Я добавлю, хотя: 'volatile' не будет исправлять проблему во всех случаях. –

4

Это может быть проблема. Это не просто задание, о котором вы должны беспокоиться. Из-за кэширования параллельные потоки могут видеть старую версию объекта, если вы не заблокируете. Таким образом, зависит ли блокировка от того, как вы ее используете, и не показываете это.

Вот free, sample chapter of "Concurrent Programming in Windows", который подробно объясняет эту проблему.

+0

Это не «кеширование». Это переупорядочение инструкций в ожидающих буферах чтения/записи. Аналогичное, но не одно и то же. Кэши в большинстве процессоров являются когерентными. Это порядок, в котором значения записываются даже в первый кеш. – tony

+0

Тони, ты прав, что переписывание инструкций связано, и неправильно, что кеширование не является. При использовании нескольких процессоров каждый имеет свой собственный кеш, который не гарантированно остается вне блокировки. См., Например: http://www.bluebytesoftware.com/blog/2009/10/20/FalseSharingIsNoFun.aspx –

+0

Извините; неправильная ссылка. Попробуйте http://www.bluebytesoftware.com/blog/2009/05/17/LoadsCannotPassOtherLoadsRevisited.aspx –

Смежные вопросы