замок внутренний замок


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

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

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

3 53

3 ответа:

lock - Это оболочка для Monitor.Enter и Monitor.Exit:

The lock ключевое слово называет Enter в начале блока и Exit в конце блока. Из документации первого:

из документации Monitor.Enter:

это законно для того же потока, чтобы вызвать Enter более одного раза без его блокировки; однако, равное количество Exit вызовы должны быть вызывается до того, как другие потоки, ожидающие объекта, разблокируются.

потому что звонки Enter и Exit сопряжены, ваш шаблон кода имеет четко определенное поведение.

обратите внимание, однако, что lock не гарантируется, что это конструкция без исключений:

A ThreadInterruptedException бросается, если Interrupt прерывает поток, ожидающий ввода lock заявление.

чтобы объяснить, почему это четко определенное поведение и никогда не подведет:

в сторону: этот ответ имеет более подробную информацию о том, как замки на самом деле работают

блокировка происходит при 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);
    }
}

согласно MSDN (см. здесь и здесь) это хорошо определенное поведение и не вызывает никаких проблем.