使用Thread.Sleep()&阻止异步Task.Yield()

时间:2017-12-30 16:48:26

标签: c# .net async-await

我了解在大多数情况下,阻止异步代码被拒绝。

但是,我有一个执行后台任务的WPF应用程序。 当用户关闭窗口时,应该取消此任务并延迟关闭窗口,直到取消和后续清理完成为止。在此期间,应阻止任何进一步的用户输入。

经过一番搜索&尝试,我想出了以下代码:

ViewModel.cs:

async void RunTaskAsync()
{
    _cancelTknSource = new CancellationTokenSource();
    try {
        await Task.Run(/*...long running calculation...*/, _cancelTknSource.Token);
    }
    catch (OperationCanceledException) { }
    finally {
        /*...cleanup...*/
        _cancelTknSource.Dispose();
        _cancelTknSource = null;            
    }
}

async Task CancelAsync()
{
   _cancelTknSource?.Cancel();
   while (_cancelTknSource != null) {
       Thread.Sleep(10);
       await Task.Yield(); //prevents dead-lock
   }
}

Window.xaml.cs:

async void Window_Closing(object sender, CancelEventArgs e)
{
    e.Cancel = true;
    await DataContext.CancelAsync();
    Close();
}

(所有这些方法都是从UI线程调用的)

这是好习惯吗? 如果没有,有哪些替代方案?

1 个答案:

答案 0 :(得分:0)

没有错误处理和清理(例如,将_cancelTknSource和_runningTask设置为null),以下代码应该这样做。但是你仍然需要在Window_Closing和实际关闭窗口之间阻止一些UI功能。

async void RunTaskAsync()
{
    using(_cancelTknSource = new CancellationTokenSource())
    {
        _runningTask =Task.Run(/*...long running calculation...*/, _cancelTknSource.Token);
        await _runningTask;
    }
}

Task CancelAsync()
{
   _cancelTknSource?.Cancel();
   return _runningTask;
}
Window.xaml.cs:

async void Window_Closing(object sender, CancelEventArgs e)
{
    e.Cancel = true;
    await DataContext.CancelAsync();
    Close();
}