简体   繁体   中英

Do events work if raised asynchronously?

I have the following skeleton of a class. As you can see in the TODO: comment I will be implementing an AsyncEnumerator construct here. This method will grab a request and pass the data off to another method to be proccessed. Based on the process I would like to call the events, either SendMilestoneReached or SendFailed. I am worried these may happen on a different thread due to the AsyncEnumerator.

Will this have an effect on the UI thread where the Webtext class will be called?

/// <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


}

Event is created by the same Thread that has raised it. This principle sounds simple but important to know.

So:

Scenario 1 App is opened. Webtext is initialised by the form in the UI thread and its send is called. Webtext sends the request synchronously and fires the event. During the whole time, all operation is done on the UI thread.

Scenario 2 App is opened. Webtext is initialised by the form in the UI thread and its send is called. Webtext sends the request Asynchronously using a worker thread. Second thread fires the event when it is finished. This will be the worker thread (background or foreground depending on the how you create the thread). Any call through this thread to UI elements needs to be done using Invoke .

As you can see, it very much depends on how you implement the send method. I cannot see any implementation of the send itself so all I can say is if you spawn a thread or use threadpool it will be on the worker thread otherwise simply sending synchronously will be on UI thread.

Note that if you're raising events asynchronously and the handlers need to update the user interface, they'll need to synchronize with the UI thread in order to update any user controls. If you raise events asynchronously, you're placing a larger burden on classes that subscribe to your events: they have to know how to do the UI thread synchronization.

For me, in general , I've found that asynchronous events aren't worth the trouble because almost invariably I end up having to handle those events in UI programs. I came to the conclusion that if I want events handled asynchronously, then the handler should take care of that.

This isn't a hard and fast rule. Not by any means. For example, System.Timers.Timer raises the event on a ThreadPool thread by default, but you can specify a SynchronizingObject so that it can synchronize with the UI thread.

If you decide to go with asynchronous events, then I suggest that you include a facility such as the Timer's SynchronizingObject so that UI clients can use your class without having to muck around with the complexities of UI thread synchronization.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM