Mat*_*don 8 c# multithreading locking race-condition
我需要使用来自第三方API的属性getter,并且只是访问该getter 有时会挂起整个应用程序,有时可以正常工作(在dev/debugger中).如果我将它部署到生产服务器,主机应用程序有时会按预期工作,有时会在KERNEL32中死于APPCRASH.
我无法理解一个简单的getter如何冻结或崩溃任何东西,所以我可能这个属性是伪装的方法,并使用我最喜欢的反编译器来查找.
这是我遇到的方案/模式:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
我是正确相信,只要_myProperty是null吸气剂调用setter和有一个竞争条件在此错误,可能导致随机/偶尔冻结我遇到?我怎样才能确认/确认这种冻结实际上是一个僵局?
什么是正确的实施?我开始相信,如果setter也有lock (Locker)(我不喜欢Locker公开访问,听起来像是要求麻烦),并且getter将分配_myProperty而不是调用setter,它是线程安全的.
最后,有没有一种方法可以调用此getter而无需第三方发送"固定"版本,而且没有冻结?
我试过从主UI线程调用它,我已经尝试从Task/后台线程调用它,我Sleep(200)在调用之前尝试过,我已经尝试设置超时Task...无论我做什么,我都不要似乎能够始终如一地称之为吸气剂并可靠地获得预期结果(它确实有效......有时候).
该Locker对象是公共的,但它定义为internal class我只能通过其接口访问,当然这不会暴露它.有没有办法我可以使用反射从外部获取锁(Monitor.TryEnter(magicallyObtainedLocker))并实际让它工作?或者那个吸气器完全被吸了?
我是否正确地相信,只要_myProperty为null,getter就会调用setter,这里有一个竞争条件错误,可能导致我遇到的随机/偶然冻结?我怎样才能确认/确认这种冻结实际上是一个僵局?
在C#中,lock可重入同一个线程.您可以在Monitor.Enter的文档中看到这一点:
如果没有阻塞,同一个线程不止一次调用Enter是合法的; 但是,在等待对象的其他线程将解除阻塞之前,必须调用相同数量的Exit调用.
不喜欢Locker可公开访问,听起来像是在寻找麻烦
我同意你的看法.这更可能是罪魁祸首.Locker公共事实很可能意味着库中的其他东西锁定了这个对象,这可能是导致死锁的原因.
如果您可以通过Visual Studio Concurrency Profiler运行它,您应该能够在死锁处暂停,并在该时间点看到阻塞的对象.