首页 > 解决方案 > 超时时间为 0 的 ManualResetEvent.WaitOne() 返回意外错误,尽管已设置事件

问题描述

我有一个包装类ManualResetEvent(见下面的代码示例)

在我的应用程序流程中,我多次WaitOne使用参数调用该方法。0true按预期返回,除了一个特定的检查返回,false尽管没有引发异常,我可以从我的日志中清楚地看到该事件已设置。

是否还有其他理由WaitOne返回false

我还将提到我有 2 个不同的引擎从具有SafeManualResetEvent成员的同一引擎继承。让我们打电话给他们AB。流程就是这样A.SafeManualResetEvent设置的,并且几次调用A.WaitOne(0)返回 true。然后,B.Set()被调用并完成。然后,A.WaitOne(0)再次调用并返回false

之后,所有A.WaitOne(0)并按预期B.WaitOne(0)返回。true有没有可能这两个实例ManualRestEvent互相干扰?

我在这里添加了一个非常抽象的示例。请注意,waitOne 调用可以来自我们应用程序中的不同线程。另请注意,此问题并非始终如一地发生。在运行这个应用程序的数千名用户中,只有一个人抱怨它,但我们仍在努力找出他的环境有什么不同。

public void Main()
    {
        PolicyEngine policy = new PolicyEngine();

        policy.WaitEngine(); //will return true because initial state is true

        policy.LoadEngine();

        policy.WaitEngine(); //will return true

        FileEngine file = new FileEngine();

        policy.WaitEngine(); //will return true

        file.LoadEngine();

        policy.WaitEngine(); //returns false - unexpected!

        policy.WaitEngine(); //returns true

        file.WaitEngine(); //returns true
    }

    public class Engine
    {
        protected virtual string GetName()
        {
            return "base";
        }

        private readonly SafeManualResetEvent _engineLoadedEvent = new SafeManualResetEvent(true);

        public Engine()
        {
            _engineLoadedEvent._name = GetName();
            Console.WriteLine("base");
        }

        public void LoadEngine()
        {
            _engineLoadedEvent.Reset();

            //some code that loads the engine

            _engineLoadedEvent.Set();
        }

        public void WaitEngine()
        {
            bool result = _engineLoadedEvent.WaitOne(new TimeSpan(0));
            Console.WriteLine($"waitOne result is: {result}");
        }
    }

    public class FileEngine : Engine
    {
        override protected string GetName()
        {
            return "file";
        }
    }

    public class PolicyEngine : Engine
    {
        override protected string GetName()
        {
            return "policy";
        }
    }

    public class SafeManualResetEvent : IDisposable
    {
        public string _name;

        public SafeManualResetEvent(bool initialState)
        {
            ManualResetEvent = new ManualResetEvent(initialState);
        }

        public ManualResetEvent ManualResetEvent { get; }

        public bool WaitOne(TimeSpan timeout)
        {
            try
            {
                Console.WriteLine($"waitOne event for {_name}");
                return ManualResetEvent.WaitOne(timeout);
            }
            catch (ObjectDisposedException)
            {
                return false;
            }
        }

        public void Reset()
        {
            try
            {
                Console.WriteLine($"reset event for {_name}");
                ManualResetEvent.Reset();
            }
            catch (ObjectDisposedException)
            {
            }
        }

        public void Set()
        {
            try
            {
                Console.WriteLine($"set event for {_name}");
                ManualResetEvent.Set();
            }
            catch (ObjectDisposedException)
            {
            }
        }

        public void Dispose()
        {
            Console.WriteLine($"dispose event for {_name}");
            ManualResetEvent.Dispose();
        }
    }

标签: c#multithreadingmanualresetevent

解决方案


推荐阅读