【问题标题】:non-immediate Task cancellation, restarting, and busy indicators非即时任务取消、重新启动和繁忙指示器
【发布时间】:2012-09-19 13:42:39
【问题描述】:

我有一个通过按钮单击触发的后台异步任务。我有一个 IsBusy 属性,该属性在任务开始时和 finally 块内更新,以说明取消或完成。

目前我的按钮点击事件会取消之前的Task,并在再次点击时启动一个新的Task;但是,由于第一个任务的取消可能会在新任务的开始之后持续存在,布尔值IsBusy 指示器可能会变得不同步。

我的问题是如何处理这种情况。

我当前的解决方案不是直接更新布尔值,而是使用在开始和完成时递增/递减的整数 - IsBusy 属性返回 BusyCount > 0。然而,这需要增加线程安全性,并且感觉不是一个好的解决方案。

另一个想法是在任务被触发时存储它,并且只启动新任务作为第一个任务的延续。这解决了取消问题,但会导致不必要的延迟(尽管是部分延迟)和调用者而不是任务的“合同”。

我最后的想法是创建一个类似于 BusyTokenSource 类的东西,它分发一次性 BusyTokens,这些 BusyTokens 从线程安全集合中添加/删除。但这似乎有点过头了。

是否有更好/正确/通用的方法来处理这种情况?

编辑:

我最终还是按照上面的最后一个想法编写了“BusyToken”类。这样,我可以简单地将函数包装在 using(BusyTokenSource.GetToken()){} 中,并让内部集合和 Dispose 处理计数和忙碌状态。

【问题讨论】:

    标签: .net wpf task-parallel-library async-await cancellation


    【解决方案1】:

    我认为每个任务应该有一个忙碌状态。不确定您的 BusyTokenSource 想法如何运作,但听起来有点像。

    创建一个持有者类:

    class BusyStatus { bool IsBusy; }
    

    并为您启动的每个任务提供一个新实例。当您不再对旧任务感兴趣时,只需丢弃旧的 BusyStatus 并创建一个新实例即可。旧任务最终将完成并设置忙碌状态,但在没有人再使用的旧实例上。

    只需确保旧任务不会意外引用新的 BusyStatus 实例即可。

    作为更一般的规则,让每个任务(或线程)在不同的数据结构上工作通常很有用。这是一个有用的一般指导原则。它使您变得简单,并轻松实现安全。

    【讨论】:

    • 感谢您的回复。根据您的上述建议,如何“汇总”所有者的整体忙碌状态(在我的情况下是视图模型)?
    • @ach,你能把“被放弃”的任务当作不忙吗?可能是有道理的,因为无论如何结果都会被丢弃。如果没有,您可能需要一个同步变量 (int) 来存储繁忙任务的数量。我想不出办法。
    • 感谢您的回复。我在上面添加了一个编辑,我使用了一次性 BusyToken 方法。效果很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-10
    • 2020-06-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多