Разница между ручным блокировкой и синхронными методами - программирование
Подтвердить что ты не робот

Разница между ручным блокировкой и синхронными методами

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

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) 
        {
            ...
        }
    }
}
4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Цитата из EE:

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

Ответ 3

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

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

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

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

Ответ 4

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

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

Ответ 5

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

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

Hasanain