【问题标题】:How do I end a thread gracefully at the point when the calling process exits or is killed?如何在调用进程退出或被杀死时优雅地结束线程?
【发布时间】:2013-06-14 04:09:06
【问题描述】:
所以我正在考虑一个类的实例,我希望线程在该类的生命周期内运行,但在调用该类的进程不再运行时终止。这不是父线程终止子线程的情况,而是单个旋转(可能在等待循环中)线程优雅退出而不持有资源等。
我认为在 C++ 中,您可以使用析构函数中的 volatile bool 来告诉线程终止,但是在 C# 中,~ 不是析构函数,它是终结器。我无法使用终结器成功终止线程。也许我在那里遗漏了一些东西。我知道更好的做法是让所有线程在不发出终止信号的情况下自然死亡,但是每次我需要做某事时都生成一个线程并不有效。是的,我知道线程池,但我认为最好让单个侦听器线程响应对类的调用,并在将类放在 gc 上时让它优雅地死掉。
我想,真正的诀窍是,我能知道,或者我怎么知道运行线程的类何时首先放在 gc 上。 IDisposable 是我要找的吗?我在这里没有使用任何非托管代码。
【问题讨论】:
标签:
c#
multithreading
garbage-collection
finalizer
【解决方案1】:
我认为你基本上有两个明智的选择。
选择一:
如果你真的没有任何非托管资源在使用,那么你可以让系统在程序关闭时关闭你的线程。这显然是最简单的解决方案。
您只需要担心您使用的对象是否具有应该调用的 dispose 方法。这包括打开的文件,但可能不包括字体之类的东西。
如果您这样做,您必须确保线程将作为“后台”线程运行。后台线程和前台线程的唯一区别是,当程序关闭时,所有后台线程都会自动终止——但前台线程不会。
如果您使用Task,默认情况下它将作为后台线程运行。
如果您的线程将对磁盘执行一些 IO 或执行其他任何不得中断的操作,您绝对不会这样做。
选择二:
添加线程取消机制,使用CancellationTokenSource并安排在程序关闭时使用,等待线程退出。
在这种情况下,您不会真正关心线程是前台还是后台,因为您将自己管理程序关闭,并且线程将在程序退出之前正确停止。
如果走这条路线,可以将线程取消逻辑和其他线程处理方法封装在一个封装线程的类中。然后你可以添加一个Dispose() 方法,这样你就可以在using 块内创建类,以确保即使在遇到异常时也能正确关闭。
我经常采用这种方法,而且似乎效果很好。