CancellationTokenSource.取消不会';在WPF应用程序退出期间无法工作

本文关键字:退出 应用程序 工作 WPF 取消 CancellationTokenSource | 更新日期: 2023-09-27 18:01:14

这里有一个简单的异步调用,带有取消代码片段。代码位于WPF应用程序类中。如果我通过WPF UI命令调用Cancel方法,异步方法将正确退出。但是,如果在OnExit方法期间调用Cancel,则不会发生任何事情。我的实际代码需要OnExit调用,因为异步方法使用了应该正确清理的IO资源。

有什么想法吗?

编辑:预期的行为是Task。当调用cancel时,Delay方法应该抛出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);
    }
}

CancellationTokenSource.取消不会';在WPF应用程序退出期间无法工作

发现问题。

WPF应用程序退出期间的Cancel调用与ListnAsync函数位于同一同步上下文中。因为线程被waitHandle阻塞了。WaitOne,ListeAsync方法无法在同一同步上下文上恢复执行。

这个问题可以通过将异步调用更改为来解决

await Task.Delay(300000, token).ConfigureAwait(false);

这允许ListeAsync函数的其余部分保留在Task的同步上下文中。延迟功能。

不确定这是否能解决手头的问题,但根据您发布的代码上下文,很可能您可以使用令牌对象的IsCancellationRequested属性,并为取消请求检查该属性,并像一样中断侦听循环

async void ListenAsync(CancellationToken token) {
    try {
        while (true) 
        {
            if(token.IsCancellationRequested)
              break;
            await Task.Delay(300000, token);
        }
    }