2013-11-30 3 views
0

Я понимаю, что блокировка .net гарантирует, что только один поток выполняет строки кода, найденные в пределах области блокировки.Является ли .Net Lock (контекст) атомом?

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

Например - Мне кажется, что если замок не атомный, то следующий код не поточно:

Class example 
{ 
    private int myNumber; 
    private object context = new object(); 

void Write() 
{ 
    myNumber--; 
} 

void WriteLock() 
{ 
    lock (context) 
    { 
     myNumber++; 
     print(myNumber); 
    } 
} 

}

Если поток А peforms метода блокировки записи() и прерывается, потому что поток B выполняет Write(), тогда myNumber может быть изменен небезопасно. Я прав?

+0

Почему бы не попробовать его в многопоточной среде? –

ответ

2

Нет, это шутки громко, как ошибка. Эти операторы не являются атомарными, хотя они выглядят так. Под капотом они работают как чтение-изменение-запись, три операции вместо одного. Таким образом, они сами не являются атомарными. Отсутствующая блокировка в Write() позволяет выполнять ее одновременно с WriteLock(). Результат произволен, в том числе без изменений, когда наступает расписание впереди WriteLock, и значение фактически уменьшается, когда WriteLock расы опережает Write.

Имея нить, прерванную, когда она владеет замком, не имеет значения, замок будет удерживаться дольше.

Использовать блокировку. Инкремент() и Decrement() для более дешевой версии, которая не нужна lock.

1

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

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

void Write() 
{ 
    lock(context) { 
    myNumber--; 
    } 
} 
+0

Эй, Дейв. Я не думаю, что дополнительный замок решил мою проблему. Что делать, если поток прерывается при выполнении кода этой блокировки? – AdiB

+1

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

+0

[блокировка] (http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx) [Монитор] (http://msdn.microsoft.com/en-us/library/hf5de04k.aspx) –