简体   繁体   English

CancellationTokenSource.Cancel在WPF应用程序退出期间不起作用

[英]CancellationTokenSource.Cancel doesn't work during WPF app exit

Here is a simple async call with cancellation code snippet. 这是带有取消代码段的简单异步调用。 The code sits in a WPF application class. 该代码位于WPF应用程序类中。 If I call the Cancel method via a WPF UI Command, the async method will exit properly. 如果我通过WPF UI命令调用Cancel方法,则异步方法将正确退出。 However, if the Cancel is invoked during the OnExit method, nothing happens. 但是,如果在OnExit方法期间调用Cancel,则不会发生任何事情。 My actual code requires OnExit call because the async method uses IO resources that should be cleaned up properly. 我的实际代码需要OnExit调用,因为async方法使用应正确清理的IO资源。

Any ideas? 有任何想法吗?

Edit: the expected behavior is that Task.Delay method should throw the OperationCancelledException when cancel is invoked. 编辑:预期的行为是,在调用cancel时Task.Delay方法应引发OperationCancelledException。 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);
    }
}

Found the problem. 找到了问题。

The Cancel call during WPF App Exit is on the same synchronization context as the ListenAsync function. WPF应用程序退出期间的Cancel调用与ListenAsync函数在同一同步上下文上。 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. 由于该线程被waitHandle.WaitOne阻止,因此ListenAsync方法无法在同一同步上下文上继续执行。

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. 这使ListenAsync函数的其余部分可以保留在Task.Delay函数的同步上下文中。

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 不知道这是否可以解决当前的问题,但是根据您发布的代码上下文,很可能您可以使用令牌对象的IsCancellationRequested属性并检查该属性是否有取消请求,并像这样退出监听循环

async void ListenAsync(CancellationToken token) {
    try {
        while (true) 
        {
            if(token.IsCancellationRequested)
              break;

            await Task.Delay(300000, token);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM