当同一事件一个接一个地被调用2次时,事件处理如何工作?

时间:2014-04-18 08:37:31

标签: c# events asynchronous delegates event-handling

假设我有一个事件表明收到了一些数据:

public event<DataEventArgs> EventHandler SomeDataReceived;
protected virtual void OnSomeDataReceived(DataEventArgs e)
{
    EventHandler handler = SomeDataReceived;
    if (handler != null)
    {
        handler(this, e);
    }
}

我有一个处理它的事件处理程序:

private void m_SomeDataReceived(object sender, DataEventArgs e)
{
    ... //handling received data
}

现在假设有些设备随机发送数据消息。有一次我在执行m_SomeDataReceived委托代码时收到一条消息。我的意思是当事件几乎同时发生时处理会发生什么?在这种情况下处理程序是并行执行还是在另一个执行之前必须等待?

1 个答案:

答案 0 :(得分:2)

是和否。如果事件发生在同一个线程上,则一个接一个地运行,但是如果每个设备都在自己的线程上运行,事件处理程序也可以在并行执行。

事件与普通方法没有什么不同。如果你想做shure他们不是在paralell执行使用锁定:

private void m_SomeDataReceived(object sender, DataEventArgs e)
{
    lock (SyncRoot)
    {
        ... //handling received data
    }
}

或者将它们放在同一个线程上:

protected virtual void OnSomeDataReceived(DataEventArgs e)
{
    EventHandler handler = SomeDataReceived;
    if (handler != null)
    {
        CONTEXT.Invoke(() => handler(this, e)); // context can e.g. be a Dispatcher from a WPF control
    }
}

在这种情况下,如果处理放弃线程(例如Application.DoEvents()await Task.Delay()),它仍然可以在第一个调用完成之前启动第二个调用!

如果事件是在同一个线程中生成的,并且您希望它们以并行方式执行,则可以执行以下操作:

public static void RaiseAsync<T>(this EventHandler<EventArgs<T>> theEvent, object sender, T args)
{
    if (theEvent != null)
    {
        var eventArgs = new EventArgs<T>(args);
        foreach (EventHandler<EventArgs<T>> action in theEvent.GetInvocationList())
            action.BeginInvoke(sender, eventArgs, null, null);
    }
}

然后,您只需拨打OnSomeDataReceived

,而不是拨打SomeDataReceived.RaiseAsync(this, args)