.NET thread safety

List.Add is an instance member. That means it's not guaranteed to be thread-safe. What does this mean?

Possibility 1. That if two threads invoke .Add on different instances, there could be an unexpected result depending on the phase of the moon?

Possibility 2. That if two threads invoke .Add on the same instance, there could be an unexpected result depending on the phase of the moon and if the instances are different there is no potential problem.

Possibility 3. Microsoft doesn't want people to use threading at all so they wrote .NET to be ambiguous.

8
задан H2ONaCl 20 June 2014 в 08:19
поделиться

5 ответов

Возможность 1 неверна. Было бы настолько необычно, если бы метод экземпляра вызывал проблемы для других экземпляров, что это было бы четко задокументировано (не только с указанием этого утверждения, но и с некоторым обоснованием, поскольку это обычно было бы признаком очень плохого кодирования, поэтому, если Следует отметить, что для этого была веская причина).

Возможность 3 не соответствует действительности, поскольку они только что задокументировали поведение потоковой передачи.

Возможность 2 частично верна. Однако взаимодействие также может происходить с одним потоком, вызывающим Add, а другим - с другим, не защищенным от потоков методом экземпляра.

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

  1. Если статический метод не является потокобезопасным, очень сложно выполнять вызовы этого метода потокобезопасным способом, особенно если класс может использоваться разными уровнями кода, написанными разными людьми. Это делает попытки сделать такие методы поточно-ориентированными почти всегда оправданными. Большинство таких членов также относительно легко сделать потокобезопасным в любом случае (если избежать наличия изменяемого статического состояния, чего всегда следует избегать).

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

Здесь упор делается на «относительно», поскольку писать потокобезопасный код не всегда легко. Иногда это довольно просто (неизменяемые классы требуют небольшой работы, чтобы сделать их небезопасными!), Но чаще это очень сложно (отсюда много вопросов по этой теме здесь и в других местах).

Тем не менее, именно поэтому в таких случаях следует возлагать бремя на пользователя. Сделать такой класс полностью потокобезопасным настолько сложно (а иногда и невозможно), что результаты будут неприемлемыми для большинства пользователей, которые лучше всех могут судить о том, какая защита необходима в конкретном случае.

10
ответ дан 5 December 2019 в 12:06
поделиться

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

Коллекции, подобные спискам в .net, обычно хранятся в массивах; если коллекция становится слишком большой для своего массива, будет выделен больший массив. Если несколько потоков имеют дело с одной и той же коллекцией и не имеют никаких блокировок, было бы возможно, чтобы один поток добавил что-то, что увеличивало бы список, а затем другие потоки попытались бы изменить список между тем, когда список был скопировано и время, когда коллекция начала использовать новый список. Это может привести к потере изменений или возникновению других неприятных событий.

0
ответ дан 5 December 2019 в 12:06
поделиться

Если два разных потока изменяют один и тот же список без синхронизации / блокировки, это может вызвать проблемы. Два потока, работающих с разными списками, подойдут. То же самое касается большинства классов - на самом деле существует очень и очень мало классов, которые явно заявляют, что «этот класс потокобезопасен», но почти все они безопасны, если вы не разделяете экземпляры (не имеете доступа к ним) между потоками. Если класс выходит из строя, даже когда потоки не разделяют экземпляры, документы скажут об этом, но это настолько уродливая ситуация, что я надеюсь, что MS не допустит его к API.

Microsoft говорит и делает то, что они делают (с точки зрения безопасности потоков) по одной важной причине:

Безопасность потоков - это сложно.

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

0
ответ дан 5 December 2019 в 12:06
поделиться

Я думаю, List.Add - плохой пример. List.Remove намного лучше, потому что на самом деле существуют серьезные проблемы с потоками. Один поток может попытаться получить доступ к элементу, тогда как другой поток попытается вызвать для него List.Remove . Теперь может случиться так, что элемент будет удален при попытке доступа к нему, что приведет к исключению NullReferenceException . В целом, однако, это в основном отказ от ответственности, поскольку не существует механизмов блокировки. Просто не забывайте блокировать всякий раз, когда два потока могут попытаться получить доступ к одному и тому же объекту или одному и тому же фрагменту кода, чтобы предотвратить такие проблемы.

4
ответ дан 5 December 2019 в 12:06
поделиться

Поскольку для членов экземпляра не реализован механизм блокировки, они помещают заявление об отказе от ответственности на веб-сайте MSDN.

См. Также Статика и безопасность потоков

и Статика и безопасность потоков: часть II

0
ответ дан 5 December 2019 в 12:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: