运行 方法异步取消支持

Run method async with cancel support

我必须从外部库调用一个方法。我无法控制它,它会阻止 UI 5 秒以上。这只是一种方法。因为我很喜欢async/await,所以我的代码是这样的:

SoundSource = await Task.Run(() => CodecFactory.Instance.GetCodec(Path));

问题是它可以持续大约 30 秒,用户想要取消它。我的第一个想法:在 GetAwaiter().OnCompleted 中设置一个 AutoResetEvent 并在 运行 中设置一个 while,它等待 AutoResetEvent 500 毫秒,然后检查 bool 变量 _cancelLoading 是否为真:

            using (var waithandler = new AutoResetEvent(false))
            {
                var x = track.GetSoundSource();
                x.GetAwaiter().OnCompleted(() => { waithandler.Set(); });
                while (!x.IsCompleted)
                {
                    await Task.Run(() => waithandler.WaitOne(500));
                    if (_cancelLoading)
                    {
                        x.GetAwaiter().OnCompleted(() => x.Result.Dispose());
                        _isLoadingSoundSource = false;
                        _cancelLoading = false;
                        return;
                    }
                }
                _isLoadingSoundSource = false;
                SoundSource = x.Result;
            }

但这不是一个好的解决方案,因为它不知道是否可以将 _isLoadingSoundSource 设置为 true,因为新方法可能仍在 运行 过程中。它可以用另一个全局 AutoResetEvent 修复,但这真的很复杂,很容易以死的样子结束。

有什么好的方法可以 "cancel" method/Task(如果任务不支持,我就不必使用它)。我不需要中止它,如果它可以 运行 直到它结束而不只是处理结果就好了。

如果您无法取消实际操作(GetCodec),那么您所能做的就是在请求取消时忽略结果

private CancellationTokenSource _cts;
async Task SetSoundSourceAsync(string path)
{
  if (_cts != null)
    _cts.Cancel();
  _cts = new CancellationTokenSource();
  var token = _cts.Token;
  var result = await Task.Run(() => CodecFactory.Instance.GetCodec(path));
  if (token.IsCancellationRequested)
    return;
  SoundSource = result;
}

上面的示例代码假定它是从 UI 线程调用的。如果不是,则 _cts.

会出现竞争条件