【问题标题】:CancellationTokenSource.Cancel doesn't work during WPF app exitCancellationTokenSource.Cancel 在 WPF 应用程序退出期间不起作用
【发布时间】:2016-08-05 19:21:56
【问题描述】:

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

有什么想法吗?

编辑:预期的行为是 Task.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);
    }
}

【问题讨论】:

  • 为什么要调用取消来进行 IO 清理。这听起来不合适。
  • 实际代码做 IO 清理。上面的示例代码只是试图让取消工作。
  • 您可能需要考虑调用 Register(Action action) 并将清理代码放入其中,而不是让循环不断运行。
  • 循环可能会分散注意力。它表示异步代码将在应用程序运行时不断运行。它只会在应用退出时终止。

标签: c# wpf asynchronous


【解决方案1】:

发现问题。

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

问题可以通过改变异步调用来解决

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

这允许 ListenAsync 函数的其余部分停留在 Task.Delay 函数的同步上下文中。

【讨论】:

    【解决方案2】:

    不确定这是否能解决手头的问题,但根据您发布的代码上下文,您可能可以使用令牌对象的IsCancellationRequested 属性并检查该属性以获取取消请求并跳出您的监听循环,例如

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多