Разница между ручным блокировкой и синхронными методами
Есть ли разница между этим:
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)
{
...
}
}
}
Ответы
Ответ 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