引发线程事件时无法访问已处置的对象

Posted

技术标签:

【中文标题】引发线程事件时无法访问已处置的对象【英文标题】:Cannot access a disposed object when raising a threaded event 【发布时间】:2016-10-12 16:24:15 【问题描述】:

我正在编写的类使用多线程,并且我为我的类创建了这个扩展方法,以便以线程安全的方式引发事件。

static class MultiThreadHelper

    public static object Raise(this MulticastDelegate eventToRaise, object sender, EventArgs e)
    
        object retVal = null;

        MulticastDelegate threadSafeMulticastDelegate = eventToRaise;
        if (threadSafeMulticastDelegate != null)
        
            foreach (Delegate d in threadSafeMulticastDelegate.GetInvocationList())
            
                var synchronizeInvoke = d.Target as ISynchronizeInvoke;
                if ((synchronizeInvoke != null) && synchronizeInvoke.InvokeRequired)
                
                    retVal = synchronizeInvoke.EndInvoke(synchronizeInvoke.BeginInvoke(d, new[]  sender, e ));
                
                else
                
                    retVal = d.DynamicInvoke(new[]  sender, e );
                
            
        

        //Return the value of the event invocation or null if none.
        return retVal;
    

当我的表单试图关闭一个挥之不去的线程时,它仍在尝试返回并引发一个不再有处理程序的事件。

我最终得到以下错误...

在该行错误发生之前我可以运行哪种检查?还有什么我可以做的或者我可以采取不同的方法来解决这个问题吗?

【问题讨论】:

【参考方案1】:

我的第一个想法是ManifestBuilder 在代理关闭时不会取消订阅。确保使用 -= 语法取消订阅。

【讨论】:

我在 ManifestBuilder 的 FormClosing 事件中这样做了。但我把它作为事件块中的最后一个动作。当我把它作为事件块中的第一个动作时,它似乎提升了这个问题。我认为我的错误是让用户在我处理类对象之前取消订阅......虽然我不明白为什么这很重要。 深入研究... 在 FormClosing 事件中,我将尝试调用将创建新线程的类的方法。然后,一旦创建了新线程,我就会取消订阅。然后......一旦线程完成它会发送一个事件(认为有一个订阅)。在处理多线程时,有什么方法可以检查任何订阅是否处于活动状态?我的问题很简单,订阅事件 -> 强制线程在计时器上发送事件 -> 取消订阅 -> 认为有订阅但没有订阅可以去的事件触发。 在进一步检查您的代码时,我会调查您在哪里获得对您传递给 Raise 方法的 eventToRaise 的引用。我唯一能想到的是,您在处置表单之前的某个时刻分配该变量,并且取消订阅事件,然后在处置表单后使用它。 是的,这似乎正是正在发生的事情......问题是正在传递的“变量”/对象将始终存在。所以检查 null 是一个失败。我从来没有找到一种方法来查看该事件是否有任何订阅,所以我只是简单地将那个调用放在一个 try-catch 块中。 ;) 解决这个问题的更好方法(而不是 try-catch)是确保控件的寿命比线程长。看看这个***问题***.com/questions/1874728/…,他们也有类似的问题。

以上是关于引发线程事件时无法访问已处置的对象的主要内容,如果未能解决你的问题,请参考以下文章

通过 Azure 函数注入 DbContext 时无法访问已处置的对象

尝试在 Web API Core 中使用 EF Core 在启动时更新数据库时出现“'无法访问已处置的对象”错误

C#:使用 IQueryable 注入 DbContext 时,无法访问 ASP.NET Core 中的已处置对象

System.ObjectDisposedException:'无法访问已处置的对象。对象名称:'OracleConnection'。'

无法访问已处置的对象。对象名称:'System.Net.Sockets.UdpClient'

无法在单元测试中访问已处置的对象