Библиотеки классов и безопасность потоков
А сейчас хотелось бы сказать несколько слов о библиотеках классов и синхрони-
зации потоков. Библиотека FCL разработки Microsoft гарантирует безопасность
в отношении потоков всех статических методов. Это означает, что одновременный
вызов статического метода двумя потоками не приводит к повреждению данных.
Механизм защиты реализован внутри FCL, поскольку нет способа обеспечить
блокирование сборок различных производителей, спорящих за доступ к ресурсу.
823
Библиотеки.классов.и.безопасность.потоков
Класс
Console
содержит статическое поле, по которому многие из его методов
устанавливают и снимают блокировку, гарантируя, что в каждый момент времени
доступ к консоли будет только у одного потока.
Кстати, создание метода, безопасного в отношении потоков, не означает, что
внутренне он реализует блокирование в рамках синхронизации потоков. Просто этот
метод предотвращает повреждение данных при попытке одновременного доступа
к ним со стороны нескольких потоков. Класс
System.Math
обладает статическим
методом
Max
, который реализован следующим образом:
public static Int32 Max(Int32 val1, Int32 val2) {
return (val1 < val2) ? val2 : val1;
}
Этот метод безопасен в отношении потоков, хотя в нем нет никакого кода бло-
кирования. Так как тип
Int32
относится к значимым, два значения этого типа при
передаче в переменную
Max
копируются, а значит, разные потоки могут одновре-
менно обращаться к данной переменной. При этом каждый поток будет работать
с собственными данными, изолированными от всех прочих потоков.
В то же время FCL не гарантирует безопасности в отношении потоков экзем-
плярным методам, так как введение в них блокирующего кода слишком сильно
сказывается на производительности. Более того, если каждый экземплярный метод
начнет выполнять блокирование и разблокирование, все закончится тем, что в при-
ложении в каждый момент времени будет исполняться только один поток, что еще
больше снизит производительность. Как уже упоминалось, поток, конструирующий
объект, является единственным, кто имеет к нему доступ. Другим потокам данный
объект недоступен, а значит, при вызове экземплярных методов синхронизация не
требуется. Однако если потом поток предоставит ссылку на объект (поместив ее
в статическое поле, передав ее в качестве аргумента состояния методу
ThreadPool.
QueueUserWorkItem
или объекту
Task
и т. п.), то тут синхронизация уже понадо-
бится, если разные потоки попытаются одновременно получить доступ к данным
не только для чтения.
Собственные библиотеки классов рекомендуется строить по этому паттер-
ну — то есть все статические методы следует сделать безопасными в отношении
потоков, а экземплярные методы — нет. Впрочем, следует оговорить, что если це-
лью экземплярного метода является координирование потоков, его тоже следует
сделать безопасным в отношении потоков. К примеру, один поток может отменять
операцию, вызывая метод
Cancel
класса
CancellationTokenSource
, а другой по-
ток, делая запрос к соответствующему свойству
IsCancellationRequested
объекта
CancellationToken
, может обнаружить, что отмена на самом деле не нужна. Внутри
этих экземплярных методов содержится специальный код синхронизации потоков,
гарантирующий их скоординированную работу
1
.
1
Поле, к которому осуществляют доступ оба члена, помечается ключевым словом volatile,
о котором мы поговорим чуть позже.
Do'stlaringiz bilan baham: |