Ответ 1
Чтобы свести к минимуму побочные эффекты, объект, который заблокирован, не должен быть объектом манипулирования, а отдельным объектом, предназначенным для блокировки.
В зависимости от ваших требований существует несколько вариантов решения этой проблемы:
Вариант A: частный объект блокировки
Выберите это, если вы просто хотите убедиться, что DoSomething
не конфликтует с параллельным экземпляром DoSomething
.
private static readonly object doSomethingLock = new object();
public static void DoSomething (string param1, string param2, SomeObject o)
{
//.....
lock(doSomethingLock)
{
o.Things.Add(param1);
o.Update();
// etc....
}
}
Вариант B: передать объект блокировки в качестве параметра
Выберите это, если доступ к o
должен быть потокобезопасным даже вне DoSomething
, то есть, если существует вероятность, что кто-то другой пишет метод DoSomethingElse
, который работает параллельно с DoSomething
и который не должен помешать блоку lock
в DoSomething
:
public static void DoSomething (string param1, string param2, SomeObject o, object someObjectLock)
{
//.....
lock(someObjectLock)
{
o.Things.Add(param1);
o.Update();
// etc....
}
}
Вариант C: создать свойство SyncRoot
Если у вас есть контроль над реализацией SomeObject
, было бы удобно предоставить объект блокировки как свойство. Таким образом, вы можете реализовать вариант B без необходимости передавать второй параметр:
class SomeObject
{
private readonly object syncRoot = new object();
public object SyncRoot { get { return syncRoot; } }
...
}
Затем вы просто используете lock(o.SyncRoot)
в DoSomething
. Для шаблона используются некоторые классы BCL, например Array.SyncLock, ICollection.SyncRoot.