Рекурсивная/вложенная блокировка в С# с оператором блокировки
Возможный дубликат:
Заблокированные блокировки на С#
Я посмотрел здесь на StackOverflow и на MSDN, и не могу поверить, что я не мог найти этот вопрос затяжным там, в интернетах.
Скажем, у меня есть класс с частным членом, который я хочу получить в нескольких общедоступных методах. Эти общедоступные методы будут вызываться разными потоками, поэтому требуется синхронизация.
public class MyClass
{
private Object SomeSharedData = new Object();
public void MethodA()
{
lock( SomeSharedData) {
// do something
MethodB();
}
}
public void MethodB()
{
lock( SomeSharedData) {
// do something
}
}
}
Обратите внимание, что MethodA и MethodB могут быть вызваны пользователями этого класса, но MethodA также вызывает MethodB, что приводит к вложенному условию блокировки.
Гарантировано ли это безопасно? Другими словами,.NET обрабатывает это по ссылке, подсчитывая блокировку, так что, когда я выхожу из этих методов, блокировка уменьшается? Или .NET выполняет некоторую магию за кулисами, посредством чего она просто игнорирует все последующие блокировки объекта, происходящего из того же потока?
Ответы
Ответ 1
Да, блокировки на основе Monitor
в .NET являются рекурсивными и считаются.
Из документов для Monitor.Enter
:
Для одного и того же потока invoke Введите несколько раз без него блокирование; однако, равное количество Вызывные вызовы должны быть вызваны до другие потоки, ожидающие объекта разблокируется.
Будет ли это хорошо или нет, для обсуждения...
Ответ 2
Да, Monitor поддержка рекурсии, но вы должны знать, потому что это поведение отличается от одного примитива синхронизации другим.
Например, ReaderWriterLockSlim по умолчанию не поддерживает рекурсию, и этот фрагмент кода генерирует исключение:
public class MyClass
{
ReaderWriterLockSlim rw = new ReaderWriterLockSlim();
//You should explicitly stated that you want to use recursion
ReaderWriterLockSlim rwWithRecursion = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
public void MethodA()
{
try {
rw.EnterReadLock();
// do something
MethodB();
}
finally {
rw.ExitReadLock();
}
}
public void MethodB()
{
try {
rw.EnterReadLock(); //throws LockRecursionException
}
finally {
rw.ExitReadLock();
}
}
}