Reputation: 198
Suppose we have a wpf window with a button named button1
that handles a void same as this:
void Button1_Clicked()
{
// configuring some new work...
// awating for this work to be completed:
while (!_WorkIsCompleted)
{
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(() => { }, System.Windows.Threading.DispatcherPriority.Background);
}
// prompting user that this works is completed.
}
And Then Suppose this UI scenario:
User clicks button1 and the void Button1_Clicked
calls. Therefore
ui thread is wating for an specific work to be completed.
At this moment user Clicks button1 again and we Start a new work (while older work is still operating and is not completed). And we await using message-loop again for this operation to be completed.
The first work is completed. But duo to message-loop architecture, user cannot receive its prompt. Because call stack waits for the later work to be completed, then returns.
Therefore, user receives prompt of later work at first, then receives prompt of sooner work.
In other words, older calls will await next calls for return. But if we use an await
keyword within an async
void we can make the true result as expected. Because of some architectural and code pattern issues i cannot use tasks in my project. and message-loop cannot make a true result for me.
I know when we use await
keyword to call an async
void (or function), it tells compiler (probably at compile time) that make some edits on programmer code to supporting await operation.
And it seems that during await, Call Stack is free to make more calls by running thread. With await
keyword, we are able to keep running thread awaited for a lot of awaited calls at a same time, that each other is not related to each other. (This behavior is what i want now.)
Actually what is happening in compiled code of an async
void, that makes await possible for multiple calls separately, with non-freezing the running thread? It must be possible for me to make a same thing for my situation. How can i edit or change my code to make a same behavior? Is there a solution in c# for this?
Upvotes: 1
Views: 93
Reputation: 456437
Actually what is happening in compiled code of an async void, that makes await possible for multiple calls separately, with non-freezing the running thread?
await
does not create a nested message loop. Instead, await
will return (after capturing a "context"). Later, when the awaited object completes, the remainder of that async
method will be posted to the context - in this case, a WPF UI context. The main message loop then picks up that message and executes the remainder of the async
method. I have an async intro that explains these basic mechanics in more detail.
How can i edit or change my code to make a same behavior?
async
/await
is a compiler-level transform; it can't be replicated just by code, unless you're willing to do all the transformations yourself (which get messy, especially with loops).
So, the easiest way to make your code work like await
is to... use await
.
The first step is to replace the boolean _IsCompleted
with a signal. In this case, the signal should be asynchronously consumable and will only be triggered once, so the appropriate type is TaskCompletionSource<T>
(for any T
):
private readonly TaskCompletionSource<object> _CompletedTcs = new TaskCompletionSource<object>();
Instead of setting _IsCompleted
to false
, you set the signal:
// was: _IsCompleted = false;
_CompletedTcs.SetResult(null);
And then you can just await
the resulting task:
// was: while (!_IsCompleted) { ... }
await _CompletedTcs.Task;
Upvotes: 2