【问题标题】:Is it necessary to cancel Task inside of finalizer?是否有必要在终结器中取消任务?
【发布时间】:2016-06-29 15:27:15
【问题描述】:

我有viewModelAviewA。我在 viewModelA 的构造函数中运行了一些耗时的操作:

public class ViewModelA
{
    Task task;
    CancellationTokenSource token;
    public viewModelA()
    {
       task = new Task(TimeConsumingOperation, token.Token);     
    }

    private void TimeConsumingMethod()
    {   
       //some time consuming operation
    }

    ~ViewModelA()
    {
       token.Cancel();
    }
}

假设我运行这个应用程序,它只包含viewAviewModelA 并且程序开始一些耗时的操作(TimeConsumingMethod()) 并且突然我想立即关闭程序,但我知道TimeConsumingMethod()仍在运行。

所以我的问题是我应该取消终结器内的任务吗?或者我不应该创建终结器方法,因为应该为非托管资源调用终结器?

【问题讨论】:

  • 嗯,如果你杀死应用程序,那不会杀死任务吗? stackoverflow.com/questions/1687677/…
  • 终结器用于释放非托管资源。您不应与终结器中的托管资源进行交互。
  • 你应该将viewModelA设为一次性,你应该取消那里的任务。
  • @AnthonyRussell 是的,你是对的,但是在接受的答案末尾有一些重要的句子“更好的方法是在关闭之前向工作人员发出信号,等待它优雅地完成,然后退出。”
  • 是的,我不确定为什么会有反对票。这是一个有效的问题。

标签: c# wpf garbage-collection task-parallel-library cancellation


【解决方案1】:

乍一看,您的提议显然是对终结器的滥用。如前所述,终结器通常用于清理非托管资源。更重要的是,终结器实际上不应成为对象契约设计的一部分。它们的存在只是为了充当有缺陷的代码的后盾,即在客户端代码未能明确执行此操作(例如通过调用 IDisposable.Dispose())时清理资源。

所以我首先要看的是non-buggy 代码应该如何与你的类交互。实际上有IDisposable 实现吗?如果没有,那么也不应该有终结器。你是否强烈地觉得你需要一个终结器?那么你的类应该实现IDisposable(或等效的),这样正确的代码才能有效地清理对象。

现在,要查看的第二件事是是否需要取消此任务。你希望通过取消任务来完成什么?除了退出进程之外,您是否预计需要在其他场景中取消任务?任务本身是如何实现的?你甚至在任何地方开始任务吗?这些都是您的问题中没有解决的问题,因此任何人都无法直接解决。

我要指出的是,假设您在某个时候调用Start() 方法,Task 对象的默认实现是使用线程池线程执行代码。线程池线程都是后台线程,当所有的前台线程都退出后,这些线程会被自动杀死,让进程自己正常终止。

因此,如果您只担心进程退出时的任务状态,并且您正在使用该任务的默认实现,并且该任务可以随时安全地中断,而不会损坏数据或保持某些临时状态处于活动状态(例如,任务完成时应删除的临时文件),那么我认为您不需要明确取消任务。

另一方面,如果出于某种原因显式取消任务,处理该问题的正确方法是提供一种机制(例如实现IDisposable 或更显式),客户端代码可以使用该机制显式通知您的对象不再需要它并且应该清理它。当客户端代码调用此机制时,您可以取消任务。

在这种情况下,您可能想要实现一个终结器,但这样做时要知道对于行为正确的客户端代码,永远不会调用该终结器。它只是为了防止行为不良的代码。同样重要的是要理解,即使对于行为不良的代码,也不能保证最终会被调用,而最有可能调用失败的情况实际上是进程退出时。

最后,如果你觉得你确实需要终结器,我强烈建议你看看SafeHandle 类。这是一个 .NET 类,您可以将其用作帮助对象的基类,该对象将抽象您的任务对象的一次性性质。这样,您自己的对象不需要自己实现终结器;相反,您实现的 SafeHandle 子类将自动满足该需求。

【讨论】:

  • 非常感谢您提供如此广泛和好的回答!:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-17
  • 1970-01-01
  • 2019-01-31
  • 1970-01-01
  • 1970-01-01
  • 2015-08-28
  • 1970-01-01
相关资源
最近更新 更多