Почему блокировка (это) {...} плохая? - PullRequest
447 голосов
/ 30 октября 2008

В документации MSDN сказано, что

public class SomeObject
{
  public void SomeOperation()
  {
    lock(this)
    {
      //Access instance variables
    }
  }
}

- это «проблема, если экземпляр доступен публично». Мне интересно почему? Это потому, что замок будет держаться дольше, чем необходимо? Или есть еще какая-то коварная причина?

Ответы [ 16 ]

1 голос
/ 03 декабря 2014

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

http://blogs.msdn.com/b/bclteam/archive/2004/01/20/60719.aspx

Таким образом, решение состоит в том, чтобы добавить частный объект, например, lockObject, в класс и поместить область кода в оператор блокировки, как показано ниже:

lock (lockObject)
{
...
}
1 голос
/ 11 июня 2013

Вот пример кода, которому проще следовать (IMO): (Будет работать в LinqPad , ссылаться на следующие пространства имен: System.Net и System.Threading.Tasks)

void Main()
{
    ClassTest test = new ClassTest();
    lock(test)
    {
        Parallel.Invoke (
            () => test.DoWorkUsingThisLock(1),
            () => test.DoWorkUsingThisLock(2)
        );
    }
}

public class ClassTest
{
    public void DoWorkUsingThisLock(int i)
    {
        Console.WriteLine("Before ClassTest.DoWorkUsingThisLock " + i);
        lock(this)
        {
            Console.WriteLine("ClassTest.DoWorkUsingThisLock " + i);
            Thread.Sleep(1000);
        }
        Console.WriteLine("ClassTest.DoWorkUsingThisLock Done " + i);
    }
}
1 голос
/ 30 октября 2008

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

Чтобы было ясно, это плохо, потому что некоторый другой кусок кода может использовать экземпляр класса для блокировки и может помешать вашему коду получить своевременную блокировку или может создать другие проблемы синхронизации потока. Лучший вариант: ничто иное не использует ссылку на ваш класс для блокировки. Средний случай: что-то использует ссылку на ваш класс для блокировки, и это вызывает проблемы с производительностью. В худшем случае: что-то использует ссылку вашего класса для блокировки, и это вызывает очень плохие, очень тонкие, действительно трудные для отладки проблемы.

0 голосов
/ 08 февраля 2019

Вы можете установить правило, которое гласит, что класс может иметь код, который блокирует «this» или любой объект, который создается кодом в классе. Так что это только проблема, если шаблон не соблюдается.

Если вы хотите защитить себя от кода, который не следует этому шаблону, то принятый ответ правильный. Но если следовать шаблону, это не проблема.

Преимущество блокировки (это) заключается в эффективности. Что делать, если у вас есть простой «объект значения», который содержит одно значение. Это просто оболочка, и она создается миллионами раз. Требуя создания частного объекта синхронизации только для блокировки, вы в основном удвоили размер объекта и удвоили количество выделений. Когда производительность важна, это преимущество.

Если вас не волнует количество выделений или объем памяти, избегать блокировки (это) предпочтительнее по причинам, указанным в других ответах.

0 голосов
/ 01 ноября 2012

Будет проблема, если к экземпляру можно получить открытый доступ, потому что могут быть другие запросы, которые могут использовать тот же экземпляр объекта. Лучше использовать приватную / статическую переменную.

0 голосов
/ 26 марта 2012

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

  • Вы не можете отменить тупик, не прерывая один из потоков, поэтому после попадания в тупик вы не сможете выйти
  • Голодание закончится автоматически после того, как один из потоков завершит свою работу

Здесь - изображение, иллюстрирующее разницу.

Заключение
Вы все еще можете безопасно использовать lock(this), если для вас не проблема с истощением потока. Вы все еще должны помнить, что когда поток, который истощает поток, используя lock(this), заканчивается блокировкой, в которой ваш объект заблокирован, он, наконец, заканчивается вечным голодом;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...