Мне нужно использовать получатель свойств из стороннего API, и просто доступ к этому получателю иногда приводит к зависанию всего приложения, иногда работает (в dev/debugger). И если я развертываю его на производственном сервере, хост-приложение иногда работает как положено, иногда умирает с APPCRASH в KERNEL32.
Я не мог понять, как простой геттер мог что-то зависнуть или разбить, поэтому я подумал, что, возможно, это свойство было замаскированным методом, и использовал свой любимый декомпилятор, чтобы выяснить это.
Это схема/шаблон, с которым я столкнулся:
internal MyClass() : ISomeInterface
{
Locker = new object();
}
public object Locker { get; private set; }
private SomeObject _myProperty;
public SomeObject MyProperty
{
get
{
lock (Locker)
{
if (_myProperty== null)
MyProperty = SomeCondition ? SomeMethod() : Something.Else;
return _myProperty;
}
}
private set
{
_myProperty = value;
}
}
Правильно ли я считаю, что всякий раз, когда _myProperty
равно null
, геттер вызывает сеттер, и здесь есть ошибка состояния гонки, которая может вызывать случайное/случайное зависание, которое я испытываю? Как я могу подтвердить/подтвердить, что это замораживание фактически является тупиком?
Какой будет правильная реализация? Меня заставили поверить, что если бы у установщика также был lock (Locker)
(мне тоже не нравится, что Locker
является общедоступным, звучит как напрашиваться на неприятности), и получатель назначал бы _myProperty
вместо вызова установщика, это было бы потокобезопасный.
Наконец, есть ли способ вызвать этот геттер, не требуя от третьей стороны отправки «исправленной» версии и без зависания?
Я пытался вызывать его из основного потока пользовательского интерфейса, я пытался вызывать его из Task
/фонового потока, я пробовал Sleep(200)
перед вызовом, я пытался установить тайм-аут для Task
... независимо от того, что я делаю, Кажется, я не могу постоянно вызывать этот геттер и надежно получать ожидаемый результат (это действительно работает... иногда).
Объект Locker
является общедоступным, но он определен в internal class
, к которому я обращаюсь только через его интерфейс, который, конечно же, не раскрывает его. Есть ли способ использовать отражение, чтобы получить блокировку извне (Monitor.TryEnter(magicallyObtainedLocker)
) и заставить ее работать? Или этот геттер полностью borked?