Всегда ли неизменяемые объекты безопасны для потоков? - PullRequest
1 голос
/ 13 ноября 2009

Можно с уверенностью предположить, что работа с неизменяемым объектом или его обход всегда будут безопасны для потоков?

Ответы [ 4 ]

9 голосов
/ 13 ноября 2009

Да. Если объект действительно неизменный, без каких-либо внутренних мутаций, то сам объект будет потокобезопасным.

(Независимо от того, обрабатываете ли вы объект и передаете его потокобезопасным способом, это другой вопрос!)

Что я подразумеваю под "внутренними мутациями"?

Многие объекты кажутся неизменными извне - например, нет установщиков свойств или других членов, которые явно вызывают мутации - но это не означает, что частные внутренние объекты объекта не способен к изменению.

Именно поэтому важно задокументировать изменчивость и безопасность потоков ваших объектов и / или их членов. В противном случае потребители вашего объекта не смогут обнаружить это без тщательного изучения внутренних компонентов (которые являются деталями реализации и могут измениться в любое время).

2 голосов
/ 13 ноября 2009

Это зависит от того, что вы подразумеваете под потокобезопасностью; Как указывает блог Эрика Липперта , этот термин может означать несколько вещей. Неизменяемые объекты гарантируют, что независимо от того, когда вы обращаетесь к свойству или методу в данном экземпляре, результат всегда будет одинаковым; это потокобезопасность для этого экземпляра. Однако, если у вас есть изменяемое поле, содержащее ссылку на неизменяемый объект, то множественные вызовы через одно и то же поле могут не относиться к одному и тому же экземпляру, следовательно, они непоследовательны (т. Е. "Threadsafe").

Я подозреваю, что для значения "threadsafe", которое вы имеете в виду, ответ - да. Но имейте в виду, что неизменные объекты не являются золотой пулей; они не делают вас невосприимчивым к взаимодействию потоков, они просто обеспечивают согласованность в одном экземпляре.

1 голос
/ 13 ноября 2009

Чтобы ответить на вопрос правильно: Нет.

Вы не можете предполагать, что неизменяемые объекты всегда безопасны для потоков.

Но, скорее всего, так и есть. См. Также обсуждение ответа Луки.

Например: доступ к методам или получателям свойств может инициировать инициализацию, которая не известна вызывающей стороне. (Например, ленивая инициализация) Эта инициализация должна быть реализована явно поточно-безопасной.

0 голосов
/ 13 ноября 2009

Сначала объект должен быть действительно неизменным - не только открытый интерфейс, но и все внутреннее состояние должно быть инициализировано. Это запрещает, например, "получить один раз, а затем кэш" или отложенной инициализации.

Во-вторых, во время построения объекты модифицируются - и из-за оптимизации и переупорядочения команд в CPU порядок записи памяти не обязательно совпадает с порядком, который вы видите в исходном коде.

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

Я недостаточно знаком с моделью mem C #, чтобы точно сказать, какая синхронизация необходима - может быть, кто-то еще может помочь (сделал сообщество вики)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...