有什么方法可以称之为吸气剂并始终如一地获得预期结果吗?

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)

我是正确相信,只要_myPropertynull吸气剂调用setter和有一个竞争条件在此错误,可能导致随机/偶尔冻结我遇到?我怎样才能确认/确认这种冻结实际上是一个僵局

什么是正确的实施?我开始相信,如果setter也有lock (Locker)(我不喜欢Locker公开访问,听起来像是要求麻烦),并且getter将分配_myProperty而不是调用setter,它是线程安全的.

最后,有没有一种方法可以调用此getter而无需第三方发送"固定"版本,而且没有冻结?

我试过从主UI线程调用它,我已经尝试从Task/后台线程调用它,我Sleep(200)在调用之前尝试过,我已经尝试设置超时Task...无论我做什么,我都不要似乎能够始终如一地称之为吸气剂并可靠地获得预期结果(它确实有效......有时候).

Locker对象是公共的,但它定义为internal class我只能通过其接口访问,当然这不会暴露它.有没有办法我可以使用反射从外部获取锁(Monitor.TryEnter(magicallyObtainedLocker))并实际让它工作?或者那个吸气器完全被吸了

Ree*_*sey 5

我是否正确地相信,只要_myProperty为null,getter就会调用setter,这里有一个竞争条件错误,可能导致我遇到的随机/偶然冻结?我怎样才能确认/确认这种冻结实际上是一个僵局?

在C#中,lock可重入同一个线程.您可以在Monitor.Enter的文档中看到这一点:

如果没有阻塞,同一个线程不止一次调用Enter是合法的; 但是,在等待对象的其他线程将解除阻塞之前,必须调用相同数量的Exit调用.


不喜欢Locker可公开访问,听起来像是在寻找麻烦

我同意你的看法.这更可能是罪魁祸首.Locker公共事实很可能意味着库中的其他东西锁定了这个对象,这可能是导致死锁的原因.

如果您可以通过Visual Studio Concurrency Profiler运行它,您应该能够在死锁处暂停,并在该时间点看到阻塞的对象.