c# 在不调用 delegate.endinvoke 的情况下从 delegate.begininvoke 捕获异常
c# catch an exception from delegate.begininvoke without calling delegate.endinvoke
我有一个监控数据库(或多个数据库)的程序。
为此,我构建了一个 class 来保存有关如何监控数据库的所有信息。
class 包含一个指向监视数据库并相应更改状态字段的函数的委托。
主线程创建 class 的新实例并调用 class.delegate.begininvoke()。
主线程循环检查每个创建的 class 的状态,并在发生任何更改时通知用户。
一个简单的代码示例:
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 中出现异常,我需要以某种方式 "transfer" 将此异常发送到主线程,但我不想开始检查状态和 Monitor 委托状态。
我很想找到一种方法来监控线程本身(由 .BeginInvoke 激活的线程),以在主线程中抛出异常。
谢谢。
I whold love to find a way to the Monitor Thread itself (the one that activated by the .BeginInvoke), to throw the exception in the Main Thread.
除了 ThreadAbortException
之类的东西,没有任何机制可以将异常注入另一个任意线程。
如果您要使用委托的 BeginInvoke()
方法,并且希望在不同于调用委托本身的线程中捕获异常,则需要调用 EndInvoke()
在该线程中。
您的另一个选择是显式地手动处理异常。 IE。在工作线程中使用 try
/catch
捕获异常,然后使用您自己选择的明确定义的机制(例如 ConcurrentQueue<T>
)将捕获的异常传递给代码 运行在主线程中。
综上所述,使用委托的 BeginInvoke()
方法从来都不是真正理想的异步执行代码的方法,而今天它更糟糕。从您的问题中不清楚 "main thread" 的性质是什么,更不用说该线程是否具有同步上下文。但假设它确实如此(例如,它是一个 GUI 线程,或者一个 ASP.NET 上下文等),那么你想要的行为很容易实现,使用 Task.Run()
开始异步操作,然后使用 await
在主线程中捕获该操作的完成以及抛出的任何异常。
就此而言,即使您的主线程当前没有同步上下文,给它一个可能是正确的方法。通过利用现有机制之一,或编写您自己的机制。这将是一个好主意,例如,如果您希望在代码中经常 运行 进入这种 "propagate the exception from the worker to the main thread" 场景。这将允许您使用内置语言支持来处理它(即 async
/await
),而不必为每个实例拼凑一些东西。实现同步上下文并非易事,但它是您可以做一次,然后一遍又一遍地重复使用的工作。
我有一个监控数据库(或多个数据库)的程序。 为此,我构建了一个 class 来保存有关如何监控数据库的所有信息。 class 包含一个指向监视数据库并相应更改状态字段的函数的委托。
主线程创建 class 的新实例并调用 class.delegate.begininvoke()。 主线程循环检查每个创建的 class 的状态,并在发生任何更改时通知用户。
一个简单的代码示例:
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 中出现异常,我需要以某种方式 "transfer" 将此异常发送到主线程,但我不想开始检查状态和 Monitor 委托状态。
我很想找到一种方法来监控线程本身(由 .BeginInvoke 激活的线程),以在主线程中抛出异常。
谢谢。
I whold love to find a way to the Monitor Thread itself (the one that activated by the .BeginInvoke), to throw the exception in the Main Thread.
除了 ThreadAbortException
之类的东西,没有任何机制可以将异常注入另一个任意线程。
如果您要使用委托的 BeginInvoke()
方法,并且希望在不同于调用委托本身的线程中捕获异常,则需要调用 EndInvoke()
在该线程中。
您的另一个选择是显式地手动处理异常。 IE。在工作线程中使用 try
/catch
捕获异常,然后使用您自己选择的明确定义的机制(例如 ConcurrentQueue<T>
)将捕获的异常传递给代码 运行在主线程中。
综上所述,使用委托的 BeginInvoke()
方法从来都不是真正理想的异步执行代码的方法,而今天它更糟糕。从您的问题中不清楚 "main thread" 的性质是什么,更不用说该线程是否具有同步上下文。但假设它确实如此(例如,它是一个 GUI 线程,或者一个 ASP.NET 上下文等),那么你想要的行为很容易实现,使用 Task.Run()
开始异步操作,然后使用 await
在主线程中捕获该操作的完成以及抛出的任何异常。
就此而言,即使您的主线程当前没有同步上下文,给它一个可能是正确的方法。通过利用现有机制之一,或编写您自己的机制。这将是一个好主意,例如,如果您希望在代码中经常 运行 进入这种 "propagate the exception from the worker to the main thread" 场景。这将允许您使用内置语言支持来处理它(即 async
/await
),而不必为每个实例拼凑一些东西。实现同步上下文并非易事,但它是您可以做一次,然后一遍又一遍地重复使用的工作。