Reputation: 3173
Here is a simple async call with cancellation code snippet. The code sits in a WPF application class. If I call the Cancel method via a WPF UI Command, the async method will exit properly. However, if the Cancel is invoked during the OnExit method, nothing happens. My actual code requires OnExit call because the async method uses IO resources that should be cleaned up properly.
Any ideas?
Edit: the expected behavior is that Task.Delay method should throw the OperationCancelledException when cancel is invoked. What I want to know is why it doesn't during app exit and if there are work around to get it behaving properly.
public partial class App : Application {
protected override void OnStartup(StartupEventArgs e) {
base.OnStartup(e);
ListenAsync(source.Token);
}
ManualResetEvent waitHandle = new ManualResetEvent(false);
CancellationTokenSource source = new CancellationTokenSource();
public void Cancel() {
source.Cancel();
}
async void ListenAsync(CancellationToken token) {
try {
while (true) {
await Task.Delay(300000, token);
}
} catch (OperationCanceledException) {
Console.WriteLine("Cancelled");
} catch (Exception err) {
Console.WriteLine(err.Message);
} finally {
Console.WriteLine("Terminate");
waitHandle.Set();
}
}
protected override void OnExit(ExitEventArgs e) {
Cancel();
waitHandle.WaitOne();
base.OnExit(e);
}
}
Upvotes: 0
Views: 920
Reputation: 3173
Found the problem.
The Cancel call during WPF App Exit is on the same synchronization context as the ListenAsync function. Because the thread is blocked by the waitHandle.WaitOne, there is no way for the ListenAsync method to resume executing on the same synchronization context.
The problem can be resolved by changing the async call to
await Task.Delay(300000, token).ConfigureAwait(false);
This allows the remainder of the ListenAsync function to stay on the sync context of the Task.Delay function.
Upvotes: 1
Reputation: 77926
Not sure if this would solve the issue at hand but per your posted code context , Well probably you can use IsCancellationRequested
property of the token object and check that property for the cancellation request and break out of your listen loop like
async void ListenAsync(CancellationToken token) {
try {
while (true)
{
if(token.IsCancellationRequested)
break;
await Task.Delay(300000, token);
}
}
Upvotes: 0