【发布时间】:2013-03-30 02:13:12
【问题描述】:
我有一个聊天会话类,它有一个 MessageReceived 事件,每当收到消息时就会引发该事件。会话类还有一个 Disconnect 事件来关闭会话并阻止接收更多消息。
public class Session
{
event EventHandler<string> MessageReceived;
public void Disconnect();
}
我订阅了 Session 的 MessageReceived 事件,并在我的处理程序中解码消息,然后使用它来更新应用程序 - 例如.. 消息可能包含有关特定用户的更新,或有关用户加入的消息,等等
当我想关闭我的应用程序时,我要做的第一件事是取消订阅 MessageReceived 事件,然后调用 Disconnect。然后我开始清理和处置应用程序使用的所有资源。
现在,如果我没有考虑太多,我可能会假设仅仅因为我取消了 MessageReceived 的订阅并调用了 Disconnect,就不可能再引发任何 MessageReceived 事件。显然情况并非如此。完全有可能在我取消订阅并调用 Disconnect 之前,事件处理程序已经启动。
这里的问题是,在我调用 Disconnect 之后,我会继续清理和处置应用程序资源,但这些资源与我的 MessageReceived 处理程序中假设可以访问的资源相同。这是一个等待发生的未处理异常。
在调用 Disconnect 之后,我想确定在继续拆卸之前不会再次调用事件处理程序。
请告诉我在这种情况下的最佳做法是什么,最好指出 .NET 框架中遇到和处理这种情况的示例。
谢谢
【问题讨论】:
-
在您取消订阅 MessageReceived 之前设置一个标志,让您知道以后收到的任何 MessageReceived 事件都应该被忽略。在事件处理程序中,只需检查标志,如果为真,则立即返回。如果您认为这可能发生在多个线程上,您可能希望使用 Volatile.Write 写入该值并使用 Volatile.Read 从中读取。
-
布尔标志是不够的。假设您在事件处理程序的开头检查标志,然后是 Thread.Sleep(5000),然后进行一些处理。标志如何停止已经检查过标志并且仍在运行的线程?
-
它不会停止线程,对此您无能为力,您只能跟踪 your 状态——在这种情况下,如果出现以下情况,您只需忽略该事件在您取消订阅后调用。即违反访问的布尔标志。