ПриМеЧание
Чтобы. лучше. познакомиться. с. данными. методами,. почитайте. про. их. Win32-
эквиваленты:.Sleep,.SwitchToThread.и.YieldProcessor .Дополнительные.сведения.
о.настройке.разрешения.системного.таймера.вы.получите.при.знакомстве.с.Win32-
функциями.timeBeginPeriod.и.timeEndPeriod
841
Конструкции.пользовательского.режима
В FCL существует также структура
System.Threading.SpinLock
, сходная
с показанным ранее классом
SimpleSpinLock
. Она отличается использованием
структуры
SpinWait
с целью повышения производительности. Структура
SpinLock
поддерживает время ожидания. Интересно отметить, что обе структуры — моя
SimpleSpinLock
и
SpinLock
в FCL — относятся к значимым типам. То есть они
являются облегченными объектами, требующими минимальных затрат памяти.
Перечислением
SpinLock
имеет смысл пользоваться, если вам нужно, к примеру,
связать блокировку с каждым элементом коллекции. Но при этом нужно следить за
тем, чтобы экземпляры
SpinLock
никуда не передавались, потому что они при этом
копируются, из-за чего вся синхронизация теряется. И хотя вы можете определять
экземплярные поля
SpinLock
, не помечайте их как предназначенные только для
чтения (
readonly
), поскольку при манипуляциях с блокировкой их внутреннее
значение должно меняться.
Универсальный Interlocked-паттерн
Многие пользователи, познакомившись с
Interlocked
-методами, удивляются, поче-
му специалисты Microsoft не разработали дополнительных методов подобного рода,
подходящих для большего количества ситуаций. К примеру, в классе
Interlocked
были бы полезны методы
Multiple
,
Divide
,
Minimum
,
Maximum
,
And
,
Or
,
Xor
и многие
другие. Однако вместо этих методов можно использовать хорошо известный шаблон,
позволяющий методом
Interlocked.CompareExchange
атомарно выполнять любые
операции со значениями типа
Int32
. А так как существуют перегруженные версии
этого метода для типов
Int64
,
Single
,
Double
,
Object
, а также для обобщенного
ссылочного типа, шаблон может работать и со всеми этими типами.
Вот пример создания на основе шаблона атомарного метода
Maximum
:
public sta
tic Int32 Maximum(ref Int32 target, Int32 value) {
Int32 currentVal = target, startVal, desiredVal;
// Параметр target может использоваться другим потоком,
// его трогать не стоит
do {
// Запись начального значения этой итерации
startVal = currentVal;
// Вычисление желаемого значения в контексте startVal и value
desiredVal = Math.Max(startVal, value);
// ПРИМЕЧАНИЕ. Здесь поток может быть прерван!
// if (target == startVal) target = desiredVal
// Возвращение значения, предшествующего потенциальным изменениям
currentVal = Interlocked.CompareExchange(
ref target, desiredVal, startVal);
// Если начальное значение на этой итерации изменилось, повторить
} while (startVal != currentVal);
продолжение
842
Do'stlaringiz bilan baham: |