Разница между ручной блокировкой и синхронизированными методами - PullRequest
53 голосов
/ 26 мая 2011

Есть ли разница между этим:

internal class MyClass
{
    private readonly object _syncRoot = new Object();

    public void DoSomething() 
    {
        lock(_syncRoot)
        {
            ...
        }
    }

    public void DoSomethingElse() 
    {
        lock(_syncRoot)
        {
            ...
        }
    }
}

и это:

internal class MyClass
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    public void DoSomething() 
    {
        ...
    }

    [MethodImpl(MethodImplOptions.Synchronized)]
    public void DoSomethingElse() 
    {
        ...
    }
}

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

Edit:

Возможно, еще один вопрос. Это:

internal class MyClass
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    public void DoSomething() 
    {
        ...
    }
}

точно так же, как это:

internal class MyClass
{
    public void DoSomething() 
    {
        lock(this) 
        {
            ...
        }
    }
}

Ответы [ 5 ]

37 голосов
/ 26 мая 2011

Первый метод предпочтительнее, потому что вы можете (и должны) сделать _syncRoot приватным. Это снижает риск взаимоблокировки.

MethodImplOptions.Synchronized - это пережиток более ранней амбициозной идеи, которая в конце концов оказалась не очень хорошей.

Относительно последнего вопроса: Да, согласно этого блога они функционально эквивалентны (но не реализованы таким же образом). И все формы lock(this) не приветствуются, опять же из-за тупиковых сценариев.

13 голосов
/ 26 мая 2011

проверить http://blogs.msdn.com/b/bclteam/archive/2004/01/20/60719.aspx и http://www.experts -exchange.com / Программирование / Языки / C_Sharp / Q_20926988.html
Они также обсуждают около lock(this) и не рекомендуют использовать его, так как:

полностью несвязанный код может также заблокировать этот объект

Цитата из EE:

Если вы заблокируете объект, все остальные потоки, которым необходим доступ к ЭТОМУ ОСОБЕННОМУ ОБЪЕКТУ, будут ожидать завершения работы другого объекта. Однако если вы пометите метод как синхронизированный, ЭТОТ ОСОБЫЙ МЕТОД не будет выполнен более чем в одном потоке. Блокировка защищает объект, Synchronized обеспечивает метод.

8 голосов
/ 26 мая 2011

Беглый взгляд и обнаружил, что портативные устройства не поддерживают MethodImplOptions.Synchronized.

Есть также замечание:

Блокировка на экземпляре или на тип, как с синхронизированным флагом, не рекомендуется для публичных типов, потому что код, кроме вашей собственной может взламывать публичные типы и экземпляров. Это может вызвать тупики или другие проблемы с синхронизацией.

источник: http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.methodimploptions%28v=VS.100%29.aspx

2 голосов
/ 26 мая 2011

Я думаю, что разница будет зависеть от того, на какие объекты ссылаются декорированные методы.Из того, что я прочитал, украшение фактически реализует lock () в IL.

Наилучшим подходом было бы сделать наиболее специфическую блокировку необходимой.

1 голос
/ 26 мая 2011

Эта статья может вам помочь: http://www.yoda.arachsys.com/csharp/threads/lockchoice.shtml

Как правило, я бы избегал блокировать 'this', поскольку частные переменные блокировки обеспечивают лучший контроль. Я бы порекомендовал заблокировать «this», если это пользовательский класс коллекции, что-то вроде SyncRoot, если это то, что требуется.

Hasanain

...