c# - 等待任务取消永远等待

标签 c# task cancellation

我有一个表单,我在其中启动一个任务来加载内容。如果用户单击取消,则此任务当然需要取消。但似乎我做错了什么。表单永远不会关闭并一直等待任务:

public partial class Designer : Form
{
    private CancellationTokenSource _cancellationTokenSource;
    private Task _loadTask;

    private async void Designer_Shown(object sender, EventArgs e)
    {
        _cancellationTokenSource = new CancellationTokenSource();
        try
        {
            _loadTask= Workbench.Instance.CurrentPackage.LoadObjects(_cancellationTokenSource.Token);
            await _loadTask;
        }
        catch (Exception ex)
        {
            Debug.Print(ex.ToString());
        }
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        _cancellationTokenSource.Cancel();
        _loadTask.Wait(); //Waits forever
        this.DialogResult = DialogResult.Cancel;
        this.Close();
    }
}

我的错在哪里?

编辑 LoadObjects()

代码
public Task LoadObjects(CancellationToken cancelToken)
{
    return Task.Run(() =>
    {
        LoadParameters(cancelToken);
        LoadConditionChecks(cancelToken);
        LoadConditonRules(cancelToken);
        LoadOperations(cancelToken);
    }, cancelToken);
}

我将 token 传递给子方法,因为循环确实存在...

最佳答案

您在等待 UI 线程并调用 Task.Wait() 时遇到了死锁。不惜一切代价避免 Task.Wait

在异步延续中为取消结果提供服务,如下所示:

private async void btnCancel_Click(object sender, EventArgs e)
{
    _cancellationTokenSource.Cancel();
    await _loadTask;
    this.DialogResult = DialogResult.Cancel;
    this.Close();
}

这是唯一可以接受 async void 的情况。

我最喜欢的异步代码专家 Stephen Cleary 提供了一篇精彩的博文,解释了为什么您应该避免将 Task.WaitTask.Result 作为阻塞机制 - Don't Block on Async Code


就其值(value)而言,当我取消时,我从不等待任务完成。我立即响应取消并让任务在后台完成。这为用户提供了响应式 UI 体验。如果我需要从已取消的任务中获得结果,我将在用户单击取消后进行一些 UI 工作以传达“等待操作结束”。

关于c# - 等待任务取消永远等待,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45501603/

相关文章:

C# 异步 CTP - 如何在不抛出 TaskCanceledException 的情况下将异步任务标记为已取消?

c# - 推荐一个关于Silverlight动画的好教程

c# - Database.ExecuteSqlCommand 始终返回 -1

c# - Linq to Xml : selecting elements if an attribute value equals a node value in an IEnumerable<XElement>

c# - 如何使用 CancellationToken 链接异步任务?

ios - NsoperationQueue 取消所有操作直到完成操作才取消

c# - 为什么 C# 需要条件句周围的括号?

c# - Task.Factory.StartNew 卡住 UI

c# - 使用多个任务从大型集合中检索所有记录

c# - 如何使用 polly 启用超时策略