Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 有没有什么方法能让我称之为“获得者”,并始终如一地获得预期的结果?_C#_Multithreading_Locking_Race Condition - Fatal编程技术网

C# 有没有什么方法能让我称之为“获得者”,并始终如一地获得预期的结果?

C# 有没有什么方法能让我称之为“获得者”,并始终如一地获得预期的结果?,c#,multithreading,locking,race-condition,C#,Multithreading,Locking,Race Condition,我需要使用来自第三方API的属性getter,仅访问该getter有时会挂起整个应用程序,有时会起作用(在dev/debugger中)。如果我将其部署到生产服务器,主机应用程序有时会按预期工作,有时会因内核32中的APPCRASH而死亡 我不明白一个简单的getter是如何冻结或崩溃任何东西的,所以我认为这个属性可能是一个伪装的方法,并使用我最喜欢的反编译器来发现 这就是我遇到的方案/模式: internal MyClass() : ISomeInterface { Locker = n

我需要使用来自第三方API的属性getter,仅访问该getter有时会挂起整个应用程序,有时会起作用(在dev/debugger中)。如果我将其部署到生产服务器,主机应用程序有时会按预期工作,有时会因内核32中的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;
    }
}
我认为只要
\u myProperty
null
,getter就会调用setter,并且这里有一个争用条件错误,这可能会导致我遇到的随机/偶尔冻结,对吗?我如何确认/确认这种冻结实际上是一种僵局

什么是正确的实现?我相信如果setter也有一个
锁(Locker)
(我也不喜欢
,听起来像是自找麻烦),getter会分配
\u myProperty
,而不是调用setter,这将是线程安全的

最后,有没有一种方法可以称之为getter,而不需要第三方提供“固定”版本,也不需要冻结

我尝试过从主UI线程调用它,我尝试过从
任务
/后台线程调用它,我尝试过
睡眠(200)
在调用之前,我尝试过在
任务
上设置超时。。。无论我做什么,我似乎都无法始终如一地称之为getter并可靠地获得预期的结果(有时它确实有效)

Locker
对象是公共的,但它是在
内部类
中定义的,我只能通过它的接口访问它,当然不会公开它。是否有一种方法可以使用反射从外部获取锁(
Monitor.TryEnter(magicallyObtainedLocker)
),并实际使其工作?或者说,这是一个完整的getter

我认为只要_myProperty为null,getter就会调用setter,并且这里有一个争用条件bug,这可能会导致我所经历的随机/偶然冻结,对吗?我如何确认/确认这种冻结实际上是一种僵局

否。在C#中,
lock
对于同一线程是可重入的。您可以在以下文档中看到:

同一线程在没有阻塞的情况下多次调用Enter是合法的;但是,在等待对象的其他线程解除阻止之前,必须调用相同数量的退出调用


我也不喜欢这个储物柜可以公开使用,听起来像是自找麻烦

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

如果可以通过VisualStudio并发探查器运行此操作,则应该能够在死锁时暂停,并在该时间点看到对象阻塞

是否有一种方法可以使用反射从外部获取锁(Monitor.TryEnter(magicallyObtainedLocker))并实际使其工作

是的,考虑到你可以反编译它,我猜是so1;以下“”:

  • “第三方”作为DLL构建在自己的独立项目中
  • “InternalLocker”是另一个项目中的控制台程序,它引用第三方DLL
我猜你可以从外面获得锁;希望但不是预测这是否足以避免僵局




我没有答案给你,但我只想对那个能手/二传手组合说“恶心!”。那太…糟糕了!@retailcoder是一个受欢迎的用户,这是有原因的——他希望避免处理这样的代码!不幸的是,我认为你最好的选择是让第三方修复他们的库:(使用你最喜欢的反编译器来找出还有谁在使用这个储物柜!在
locker
上查找用法会产生很少的结果,所有的getter都是这样设置的,都在同一个类中;但是这个getter是唯一一个调用setter的getter。看起来是公开的,带有YAGNI标记…@retailcoder你得到了一个appcrash sugg它可能是
SomeMethod
或getter中访问的某个属性中的一个问题,事实上……因此它与属性自身的运行和多线程处理无关?@retailcoder属性“自身的运行”很好。死锁可能会给出不同的行为,因为它只会导致无限挂起。。。
using System;

namespace ThirdParty
{
    public interface ISomeInterface
    {
        string MyProperty { get; }
    }

    public static class Factory
    {
        public static ISomeInterface create() { return new MyClass(); }
    }

    internal class MyClass : ISomeInterface
    {
        internal MyClass()
        {
            Locker = new object();
        }

        public object Locker { get; private set; }

        private string _myProperty;
        public string MyProperty
        {
            get
            {
                lock (Locker)
                {
                    if (_myProperty == null)
                        MyProperty = "foo";
                    return _myProperty;
                }
            }

            private set
            {
                _myProperty = value;
            }
        }
    }
}
using System;
using System.Linq;

using System.Reflection;
using System.Threading;
using ThirdParty;

namespace InternalLocker
{
    class Program
    {
        static void Main(string[] args)
        {
            test1();
            test2();
        }

        static void test1()
        {
            ISomeInterface thing = Factory.create();
            string foo = thing.MyProperty;
            assert(foo == "foo");
        }

        static void test2()
        {
            ISomeInterface thing = Factory.create();
            // use reflection to find the public property
            Type type = thing.GetType();
            PropertyInfo propertyInfo = type.GetProperty("Locker");
            // get the property value
            object locker = propertyInfo.GetValue(thing, null);
            // use the property value
            if (Monitor.TryEnter(locker))
            {
                string foo = thing.MyProperty;
                Monitor.Exit(locker);
                assert(foo == "foo");
            }
            else
                assert(false);
        }

        static void assert(bool b)
        {
            if (!b)
                throw new Exception();
        }
    }
}