【发布时间】:2020-05-06 20:12:14
【问题描述】:
我有一个监控一个数据库(或多个数据库)的程序。 为此,我构建了一个包含有关如何监视数据库的所有信息的类。 该类包含一个委托,该委托指向一个监视数据库并相应更改状态字段的函数。
主线程创建一个新的类实例并调用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 激活的线程),以便在主线程中引发异常。
谢谢。
【问题讨论】:
-
您在这里基本上重新实现的是轮询,不是一次而是两次,并且以最低效的方式进行。你检查过你的数据库,看看它是否已经有办法做到这一点?另见What is the X Y Problem?
-
如果您使用
delegate.BeginInvoke,您必须调用EndInvoke,否则您的委托将永远不会被处置。如果您想从委托中获取结果(包括异常)而不进行处理,您应该使用completion callback。 -
罗伯特哈维这是我试图解决的问题的一个例子。我并没有真正检查数据库本身,而是检查数据库中的数据,CheckDB 函数从数据库中获取数据并检查它。如果数据超出预定义的限制(或对数据进行其他检查),则会引发警报状态。我希望主线程检查何时引发警报状态并采取相应措施。
-
Dour High Arch,如果我弄错了,请纠正我,但是当函数结束时,代表没有被处理?即当 state == 3 时?
-
不,函数结束时不会释放委托,因为它对您的类是全局的,而不是方法的局部。看看你的类,
private MonitorHandlerDelegate mainHandler是类实例,而不是本地实例。是的,如果您的代表没有外部状态或资源,那么 not disposing it won't leak resources,但这是非常危险的 you should always callEndInvoke。
标签: c# multithreading exception delegates