代码之家  ›  专栏  ›  技术社区  ›  Romen

什么可以导致此事件停止被调用?

  •  1
  • Romen  · 技术社区  · 7 年前

    问题是:

    我在一个类中使用异步事件处理,该类每秒调用事件60次。如果我运行该软件几个小时,我发现它最终会进入一种状态,在这种状态下,事件将停止调用指定的委托,而不会看到任何异常或用户输入。

    以下是我正在使用的事件代码的精简版本:

    class DataSource
    {
        public event EventHandler<DataReadyEventArgs> DataReady;
    
        private void OnDataReady()
        {
            EventHandler<DataReadyEventArgs> evt = DataReady;
            if (evt != null)
            {
                Trace.WriteLine("Invoking DataReady...");
                DataReadyEventArgs args = new DataReadyEventArgs();
                evt.BeginInvoke(this, args, new AsyncCallback(DataReadyHandled), null);
            }
        }
    
        private void DataReadyHandled(IAsyncResult result)
        {
            AsyncResult aresult = result as AsyncResult;
            EventHandler<DataReadyEventArgs> evt = aresult.AsyncDelegate as EventHandler<DataReadyEventArgs>;
            if (evt != null)
            {
                try
                {
                    evt.EndInvoke(result);
                    Trace.WriteLine("DataReady was handled.");
                }
                catch
                { }
            }
        }
    }
    
    class DataConsumer
    {
        public DataConsumer(DataSource src)
        {
            src.DataReady += HandleDataReady;
        }
    
        public void HandleDataReady(object sender, DataReadyEventArgs e)
        {
            Trace.WriteLine("Handling DataReady");
        }
    }
    

    为了避免写出进一步的代码来提供完整的图片,您还可以做出以下假设:

    • 人们总是强烈地提到 DataSource 实例,以便在 DataConsumer
    • 这个 数据使用者 将其处理程序方法附加一次,并且在垃圾回收实例之前不会将其移除。

    这是奇怪的部分;当我将调试器附加到处于中断状态的软件时,我可以看到 evt OnDataReady() 引用 EventHandler 实例,不为空。它实际上叫BeginInvoke但是 HandleDataReady 方法从未输入。调试器显示 事件处理程序 基类的方法属性为空。我好像不明白为什么 事件处理程序

    我最好的猜测是:

    我的应用程序中完全不相关的东西是否会损坏 事件处理程序 ? 我同时使用本机和托管c++库。


    更新:

    我最好的猜测是不太可能的,因为我已经运行了一些其他的测试,使我合理地确定本机库没有泄漏或损坏内存。

    在用另一次日志记录再现问题之后,我可以看到事件并没有完全停止,而是以大约19小时的间隔被调用!显然,处理程序委托中有一个长时间运行的操作或阻塞。

    为了确定这是我的代码而不是.NET,我有一个更新的问题。。。

    第二个问题:

    .NET(4.5)或其垃圾收集器中是否内置了可以阻止调用事件处理程序的行为?

    0 回复  |  直到 7 年前
    推荐文章