c# - 有什么方法可以调用这个 getter 并始终如一地获得预期结果吗?

标签 c# multithreading locking race-condition

我需要使用来自第 3 方 API 的属性 getter,只是访问该 getter 有时 会挂起整个应用程序,有时 工作(在开发/调试器中) .如果我将它部署到生产服务器,主机应用程序有时会按预期工作,有时会因 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;
    }
}

我相信每当 _myPropertynull 时,getter 调用 setter 并且这里有一个 race condition bug 是否正确?导致我遇到的随机/偶尔卡住?我如何确认/证实此卡住实际上是一个死锁

什么是正确的实现?我被引导相信,如果 setter 也有一个 lock (Locker)(我也不喜欢 Locker 可以公开访问,听起来像是自找麻烦) ,getter 将分配 _myProperty 而不是调用 setter,它是线程安全的。

最后,有没有一种方法可以在不需要第 3 方发布“固定”版本且不卡住的情况下调用此 getter?

我试过从主 UI 线程调用它,我试过从 Task/后台线程调用它,我试过 Sleep(200)调用,我尝试在 Task 上设置超时...无论我做什么,我似乎都无法始终如一地调用该 getter 并可靠地获得预期结果(它 确实工作......有时)。

Locker 对象是公共(public)的,但它是在一个内部类 中定义的,我只能通过它的接口(interface)访问它,当然不会公开它。有没有一种方法可以使用反射从外部获取锁 (Monitor.TryEnter(magicallyObtainedLocker)) 并让它真正起作用?或者是 setter/getter 完全borked

最佳答案

Am I correct to believe that whenever _myProperty is null, the getter calls the setter and there's a race condition bug here that may be causing the random/occasional freezing I'm experiencing? How can I confirm/infirm that this freezing is effectively a deadlock?

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

It is legal for the same thread to invoke Enter more than once without it blocking; however, an equal number of Exit calls must be invoked before other threads waiting on the object will unblock.


don't like the Locker being publicly accessible either, sounds like asking for trouble

我同意你的看法。这更有可能是罪魁祸首。 Locker 是公共(public)的这一事实很可能意味着库中的其他东西正在锁定此对象,这可能是死锁的原因。

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

关于c# - 有什么方法可以调用这个 getter 并始终如一地获得预期结果吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21489069/

相关文章:

C++ 在类中创建线程给出 c2064

java - 为什么它不会造成僵局?

c++ - std线程调用模板类: compiler error的模板成员函数

C#:CompareTo(String) 和 Equals(String) 有什么区别?

c# - 如果没有异常,是否可以有条件地执行一条语句?

c# - 正确阅读 XML 有困难

java - 如何在长时间运行的操作开始之前/同时显示进度屏幕?

sql-server - 在 SQL Server 中强制查询超时

c++ - 如果我锁定变量,是否必须将复杂类型标记为 `volatile`?

c# - NAudio 峰值音量计