如果异步引发事件会有效吗?

时间:2010-11-20 23:45:09

标签: c# events asynchronous thread-safety

我有一个类的以下骨架。正如你在TODO中看到的那样:注释我将在这里实现一个AsyncEnumerator构造。此方法将获取请求并将数据传递给另一个要进行处理的方法。基于该过程,我想调用事件,SendMilestoneReached或SendFailed。我担心由于AsyncEnumerator,这些可能发生在不同的线程上。

这会对将调用Webtext类的UI线程产生影响吗?

/// <summary>
/// Sends Webtexts.
/// </summary>
public class Webtext
{
    #region Event Definitions

    // Events.
    public event EventHandler<SendingEventArgs> SendStarted = delegate { };
    public event EventHandler<SendingEventArgs> SendFailed = delegate { };
    public event EventHandler<SendingEventArgs> SendSuccessful = delegate { };
    public event EventHandler<SendingEventArgs> SendMilestoneReached = delegate { };

    // Shared EventArgs Object, Consumed by the Events.
    SendingEventArgs EventArgs = new SendingEventArgs();

    #endregion

    /// <summary>
    /// Executes the send request.
    /// </summary>
    /// <param name="Operator">The operator whos service to use.</param>
    /// <param name="Username">The username of the requested operator.</param>
    /// <param name="Password">The password of the requested operator.</param>
    /// <param name="Content">The content to send.</param>
    /// <param name="Recipient">The recipient to recieve the content.</param>
    public void ExecuteSendRequest(string Operator, 
                                   string Username, 
                                   string Password, 
                                   string Content, 
                                   string Recipient)
    {
        //TODO: Implement Async requests here.
    }

    #region Event Handlers

    /// <summary>
    /// Called when [sending started].
    /// </summary>
    protected void OnSendingStarted()
    {
        SendStarted(this, EventArgs);
    }

    /// <summary>
    /// Called when [send fail].
    /// </summary>
    protected void OnSendFail()
    {
        SendFailed(this, EventArgs);
    }

    /// <summary>
    /// Called when [send successful].
    /// </summary>
    protected void OnSendSuccessful()
    {

        SendSuccessful(this, EventArgs);
    }

    /// <summary>
    /// Called when [send milestone reached].
    /// </summary>
    protected void OnSendMilestoneReached()
    {
        SendMilestoneReached(this, EventArgs);
    }

    #endregion


}

2 个答案:

答案 0 :(得分:3)

事件由引发它的同一Thread创建。这个原则听起来很简单但很重要。

所以:

场景1 应用已打开。 Webtext由UI线程中的表单初始化,并调用其发送。 Webtext发送请求同步并触发事件。在整个过程中,所有操作都在UI线程上完成。

场景2 应用已打开。 Webtext由UI线程中的表单初始化,并调用其发送。 Webtext使用工作线程发送请求异步。第二个线程在完成时触发事件。这将是工作线程(背景或前景,具体取决于您创建线程的方式)。通过此线程对UI元素的任何调用都需要使用Invoke完成。

正如你所看到的,它在很大程度上取决于你如何实现send方法。我看不到发送本身的任何实现所以我只能说是你生成一个线程或使用线程池它将在工作线程上,否则只需在UI线程上同步发送。

答案 1 :(得分:3)

请注意,如果您异步引发事件并且处理程序需要更新用户界面,则需要与UI线程同步以更新任何用户控件。如果异步引发事件,则会给订阅事件的类带来更大的负担:他们必须知道如何进行UI线程同步。

对我来说,一般,我发现异步事件不值得麻烦,因为我几乎总是不得不在UI程序中处理这些事件。我得出结论,如果我想要异步处理事件,那么处理程序应该处理它。

这不是一个硬性规定。绝不是。例如,System.Timers.Timer默认情况下会在ThreadPool线程上引发事件,但您可以指定SynchronizingObject以便它可以与UI线程同步。

如果您决定使用异步事件,那么我建议您添加一个工具,例如Timer的SynchronizingObject,以便UI客户端可以使用您的类,而不必考虑UI线程同步的复杂性。

相关问题