Подтвердить что ты не робот

Замок внутри замка

Мне интересно, приведет ли эта конструкция к ошибке:

lock(sync)
{
  // something
  lock(sync)
  {
    //something
    lock(sync)
    {
      //something
    }
  }
}

Я запустил этот код, и он кажется прекрасным, но, может быть, в некоторых случаях может возникнуть ошибка?

4b9b3361

Ответ 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 (здесь здесь и здесь) это четко определенное поведение и не вызывает проблем.