这是一个带有取消代码段的简单异步调用。代码位于WPF应用程序类中。如果我通过WPF UI命令调用Cancel方法,则异步方法将正确退出。但是,如果在OnExit方法期间调用Cancel,则不会发生任何事情。我的实际代码需要OnExit调用,因为异步方法使用应该正确清理的IO资源。
有什么想法吗?
编辑:预期的行为是Task.Delay方法应该在调用cancel时抛出OperationCancelledException。我想知道的是,为什么它在应用程序退出期间没有,以及是否有解决方法让它正常运行。
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);
}
}
答案 0 :(得分:1)
发现问题。
WPF App Exit期间的Cancel调用与ListenAsync函数位于同一上下文中。由于线程被waitHandle.WaitOne阻塞,因此ListenAsync方法无法在同一个同步上下文中继续执行。
可以通过将异步调用更改为
来解决此问题await Task.Delay(300000, token).ConfigureAwait(false);
这允许ListenAsync函数的其余部分保留在Task.Delay函数的同步上下文中。
答案 1 :(得分:0)
不确定这是否可以解决手头的问题,但是根据您发布的代码上下文,很可能您可以使用令牌对象的IsCancellationRequested
属性并检查该属性以获取取消请求并突破您的侦听循环像
async void ListenAsync(CancellationToken token) {
try {
while (true)
{
if(token.IsCancellationRequested)
break;
await Task.Delay(300000, token);
}
}