Класс SpinLock в C#

В библиотеке .NET 4.0 BCL появился новый тип System.Threading.SpinLock. Его определенно следует использовать вместо класса MySpinLock. SpinLock должен использоваться, когда есть обоснованные ожидания относительно того, что захват блокировок редко будет связан с ожиданием.

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

Кроме того, как и MySpinLock из предыдущего раздела, блокировка SpinLock не может быть захвачена реентерабельно. То есть если поток уже владеет блокировкой, попытка захватить ее опять приведет к генерации исключения, если передано true в качестве параметра enableThreadOwnerTracking конструктора SpinLock, или к возникновению взаимной блокировки.

Отслеживание владельца потока в SpinLock на самом деле предназначено для использования при отладке.

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

Поэтому, вероятно, стоит начинать с использования более высокоуровневых и гибких механизмов блокировки, которые жертвуют эффективностью в пользу гибкости. Затем, если во время тестирования и профилирования будет определено, что должен использоваться более легковесный механизм блокировки, можно обратиться к SpinLock.

SpinLock — тип значения. Поэтому соблюдайте осторожность, избегая излишнего копирования и упаковки, иначе могут возникнуть неожиданные сюрпризы. Например, если SpinLock требуется передать в качестве параметра методу, передавайте его по ссылке (ref), чтобы избежать лишнего копирования.

Чтобы продемонстрировать использование SpinLock, предыдущий пример был модифицирован для замены MySpinLock на SpinLock, как показано ниже:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using System;
using System.10;
using System.Threading;
public class EntryPoint {
static private Random rnd = new Random();
private static SpinLock logLock = new SpinLock( false );
private static StreamWriter fsLog = new StreamWriter ( File.Open("log.txt",
FileMode.Append, FileAccess.Write, FileShare.None) );
private static void RndThreadFunc ()  { 
bool lockTaken = false; 
logLock.Enter ( ref lockTaken );
if ( lockTaken )  { 
try {
fsLog.WriteLine ( "Поток запускается" ); 
fsLog.Flush ();
}
finally {
logLock.Exit ();
}
int time = rnd.Next ( 10, 200 ); 
Thread.Sleep ( time ); 
lockTaken = false; 
logLock.Enter ( ref lockTaken ); 
if ( lockTaken )  { 
try {
fsLog.WriteLine ( "Поток завершается" ); 
fsLog.Flush();
}
finally {
logLock.Exit ();
}
static void Main()  {
// Запустить потоки, ожидающие в течение случайного периода времени. 
Thread[] rndthreads = new Thread[ 50 ]; 
for( uint i = 0; 
i < 50; 
++i )  { 
rndthreads[i] = new Thread( new ThreadStart(
EntryPoint.RndThreadFunc)  ); 
rndthreads[i].Start();
}

В коде есть очень важные моменты, на которые следует обратить внимание. Вызов SpinLock.Enter принимает ссылку ref на переменную bool. Эта переменная bool указывает на то, была ли установлена блокировка. Таким образом, после вызова Enter она должна быть проверена.

Но что более важно — перед вызовом Enter эта переменная bool должна быть инициализирована значением false. В классе SpinLock не реализован интерфейс IDisposable, поэтому он не можете использоваться вместе с блоком using, так что вместо гарантии правильной очистки применяется конструкция try/finally. Если бы команда разработчиков BCL реализовала IDisposable в SpinLock, пришлось бы ожидать катастрофы.

Дело в том, что всякий раз, когда выполняется приведение экземпляра к типу реализуемого им интерфейса, производится упаковка типа значения. Упаковка крайне нежелательна для экземпляров SpinLock, и ее следует всячески избегать.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100