Замок внутри замка
Мне интересно, приведет ли эта конструкция к ошибке:
lock(sync)
{
// something
lock(sync)
{
//something
lock(sync)
{
//something
}
}
}
Я запустил этот код, и он кажется прекрасным, но, может быть, в некоторых случаях может возникнуть ошибка?
Ответы
Ответ 1
lock
является оберткой для Monitor.Enter
и Monitor.Exit
:
Ключевое слово lock
вызывает Enter
в начале блока и Exit
в конце блока. Из прежней документации:
Из документации для Monitor.Enter
:
В том же потоке законно ссылаться Enter
более одного раза без блокировки; однако необходимо вызывать равное количество вызовов Exit
, прежде чем другие потоки, ожидающие этого объекта, будут разблокированы.
Поскольку вызовы Enter
и Exit
сопряжены, ваш шаблон кода имеет четко определенное поведение.
Обратите внимание, однако, что lock
не гарантируется быть конструкцией без исключений:
A ThreadInterruptedException
вызывается, если Interrupt
прерывает поток, ожидающий ввода инструкции lock
.
Ответ 2
Чтобы объяснить, почему это четко определенное поведение и никогда не потерпит неудачу:
Помимо этого: Этот ответ содержит более подробные сведения о том, как работают блокировки
Блокировка происходит на уровне Thread
, поэтому вызов второй раз в том же потоке будет избыточным. Я бы подумал, что у него не будет никакого штрафа за производительность (хотя это будет зависеть от того, как написаны внутренние компоненты .Net, поэтому я не могу этого гарантировать)
Много раз у вас была бы общедоступная функция, которая вызывает другую публичную функцию в вашем классе, которой обоим нужен замок при использовании отдельно. Если это не было разрешено, следующее:
private Dictionary<string, int> database = new Dictionary<string, int>();
private object databaseLock = new object();
public void AddOrUpdate(string item)
{
lock (databaseLock)
{
if (Exists(item))
database.Add(item, 1);
else
++database[item];
}
}
public bool Exists(string item)
{
lock (databaseLock)
{
//... Maybe some pre-processing of the key or item...
return database.ContainsKey(item);
}
}
Ответ 3
В соответствии с MSDN (здесь здесь и здесь) это четко определенное поведение и не вызывает проблем.