2
我不知道是否是这个触发在C#中的事件的方式:如何安全地触发事件?
public event EventHandler<ActionEventArgs> ActionDataReceived;
public void showLog(string logMessage)
{
ActionDataReceived(this, new ActionEventArgs(logMessage));
}
我不知道是否是这个触发在C#中的事件的方式:如何安全地触发事件?
public event EventHandler<ActionEventArgs> ActionDataReceived;
public void showLog(string logMessage)
{
ActionDataReceived(this, new ActionEventArgs(logMessage));
}
的安全的方式是采取处理程序的副本,并提高该替代即
var handler = ActionDataReceived;
if (handler != null)
{
handler(this, new ActionEventArgs(logMessage));
}
这将在尝试提升之前减轻可能导致事件未被分配的竞争条件。
由于@EricLippert指出这不覆盖在处理器的内部状态改变发生后转让的情形。
var temp = ActionDataReceived;
if (temp != null)
temp();
有关详细说明,请参阅this post of Eric Lippert。
我向你保证,它不会减轻任何**竞争条件;它只会减轻竞争条件,因此在检查无效后将事件更改为空。例如,假设我们在线程Alpha和Bravo之间有以下种族:Alpha将委托复制到处理程序并检查它是否为空。然后Bravo从事件处理程序列表中删除方法M,并*销毁M需要正确操作的状态*假设不正确,那么M永远不会再被调用,因为它不再是处理程序。然后Alpha调用M,这会爆炸。 – 2013-05-07 17:15:36
这种模式根本不能缓解那场比赛;如果那是你所处的状况,那么你必须找到一些其他方式来缓解比赛。一般来说,最好的办法是:如果你这样做会伤害你,不要这样做。多线程程序中的处理程序应该总是处于可安全调用的状态,而不管它是否当前注册为处理程序或不处理。 – 2013-05-07 17:16:54
@EricLippert由*任何*竞争条件我指的是事件可能未被分配/更改的任何情况。但是,从你所说的处理程序仍然可以改变?这是我的理解,一旦你拿了一个处理程序的副本,它会按原样执行(不管它在调用之前是否随后被更改)。 – James 2013-05-08 08:16:33