首页 > 解决方案 > c# 从delegate.begininvoke 捕获异常而不调用delegate.endinvoke

问题描述

我有一个监控数据库(或多个数据库)的程序。为此,我构建了一个包含有关如何监视数据库的所有信息的类。该类包含一个委托,该委托指向一个监视数据库并相应更改状态字段的函数。

主线程创建该类的一个新实例并调用 class.delegate.begininvoke()。主线程循环检查每个创建的类的状态,并在发生任何更改时通知用户。

一个简单的代码示例:

Class Monitor
{
    private Object lockObj;
    private delegate void MonitorHandlerDelegate();
    private MonitorHandlerDelegate mainHandler;

    private int State;
    private int DBid;

    public Monitor(int DBid)
    {
        this.DBid = DBid;
        mainHandler += MonitorHandler;
        lockObj = new Object();
    }

    private void MonitorHandler()
    {
        do
        {
            state = CheckDB(DBid); // 0 is ok, 1 is fail, 2 is InWork, 3 is stop monitoring
        } while (state != 3);
    }

    public int state
    {
        get { lock(lockObj) { return State;} }
        set { lock(lockObj) {State = value;} }
    }

    public void Start()
    {
        this.state = 0;
        this.mainHandler.BeginInvoke(null, null);
    }
}

public Main()
{
    Monitor firstMonitor = new Monitor(20);
    firstMonitor.Start();
    do
    {
        if(firstMonitor.state == 1) WriteLine("DB 20 stop working");
    } while(true);
}

我遇到的问题是异常处理,如果 MonitorHandler 函数抛出异常,我没有办法知道它。

我不调用 EndInvoke 所以异常不会重新抛出到主线程。

我的目标是通过简单地检查监视器实例的状态字段来检查数据库状态。如果 throwen 中出现异常,我需要以某种方式将此异常“转移”到主线程,但我也不想开始检查状态和 Monitor 委托状态。

我很喜欢找到一种方法来监视监视器线程本身(由.BeginInvoke 激活的那个),以便在主线程中引发异常。

谢谢你。

标签: c#multithreadingexceptiondelegates

解决方案


我很喜欢找到一种方法来监视监视器线程本身(由.BeginInvoke 激活的那个),以便在主线程中引发异常。

除了类似的东西ThreadAbortException,没有将异常注入另一个任意线程的机制。

如果要使用委托的BeginInvoke()方法,并且希望在与调用委托本身不同的线程中捕获异常,则需要调用EndInvoke()该线程。

您的另一个选择是显式手动处理异常。即在工作线程中使用try/捕获异常catch,然后使用您自己选择的明确定义的机制(例如 a ConcurrentQueue<T>)将捕获的异常传递给在主线程中运行的代码。

话虽如此,使用委托的BeginInvoke()方法从来都不是像那样异步执行代码的理想方法,而今天它甚至更糟糕。从您的问题中不清楚“主线程”的性质是什么,更不用说该线程是否具有同步上下文。但假设它确实如此(例如,它是一个 GUI 线程,或一个 ASP.NET 上下文等),那么您想要的行为很容易实现,使用Task.Run()启动异步操作,然后await在主线程中使用来捕获该操作的完成,以及抛出的任何异常。

就此而言,即使您的主线程当前没有同步上下文,也可能是正确的方法是给它一个。通过利用现有机制之一,或编写自己的机制。例如,如果您希望在代码中经常遇到这种“将异常从工作线程传播到主线程”的场景,这将是一个好主意。这将允许您使用内置语言支持来处理该问题(即async/ await),而不必为每个实例拼凑一些东西。实现同步上下文并非易事,但您可以完成一次工作,然后一遍又一遍地重复使用。


推荐阅读