How to return awaitable (Task?) that waits for an

2019-07-10 02:35发布

问题:

I have threads:

  1. UI thread with Dispatcher loop
  2. background thread that listens for messages in a queuing framework.

when a message is received, an event is fired in the background thread:

messageReceiver.Received += (sender, args) => ...

In UI thread I would like to await a message, something like this:

void ButtonClicked(object sender, RoutedEventArgs e) {
    await NextMessage(); //should return when messageReceiver.Received is fired
}

How to implement awaitable NextMessage method, so it does not create new thread each time?

There is SemaphoreSlim class where I can await WaitAsync, but is seems to create new thread that is blocked until SemaphoreSlim is released.

Maybe TaskCompletionSource is the way to go? Which TaskCreationOption should I use then?

回答1:

You mentioned the TaskCompletionSource and that is what I believe you need here. You'd tether it to the .Received event like so:

static Task<IEnumerable<Message>> FromEvent(Receiver messageReceiver)
{
    var tcs = new TaskCompletionSource<IEnumerable<Message>>();

    EventHandler<IEnumerable<Message>> handler = null;
    handler = (o, e) =>
        {
            messageReceiver.Received -= handler;
            tcs.SetResult(e.Messages);
        };
    messageReceiver.Received += handler;

    return tcs.Task;
}

Then you could await it like this:

// Having the async keyword is fine here since this is an event handler 
async void ButtonClicked(object sender, RoutedEventArgs e) 
{
    var messages = await FromEvent(messageReceiver);
}