问题 是否应始终在C#中保持对正在运行的Thread对象的引用?


或者可以做这样的事情:

new Thread( new ThreadStart( delegate { DoSomething(); } ) ).Start();

我似乎记得在这种情况下,Thread对象将被垃圾收集,但底层的OS线程将继续运行,直到委托的末尾传递给它。我基本上是在寻找ThreadPool功能,但不希望线程成为后台线程(即我希望它们让应用程序保持活动状态)。

更新: 
根据Jason的说法,CLR实际上在运行时保持对Thread对象的内部引用,因此在线程退出之前不会对其进行垃圾回收。


4364
2017-12-24 04:34


起源

考虑这一点的一种方法是,“如果对象不存在,孤立线程中的执行逻辑如何能够调用System.Threading.Thread.CurrentThread?” - Jason Jackson
杰森,你假设有人会想到在第一时间试试这个。 ... 我的意思是 一世 当然会......嘿......呃... =( - Brent Rittenhouse


答案:


我一般发现,如果我需要像你在你的例子中那样直接启动一个新线程,而不是从线程池中获取一个,那么它是一个长时间运行的线程,我将需要稍后引用它来杀死它对于短期运行线程,如在后台线程上调用IO等,我总是使用线程池线程(通常间接通过someDelete.BeginBlah(...)方法调用)。当使用这样的线程池线程时,我更喜欢不保留引用。我不知道另一个程序员是否可能不恰当地使用对该线程的引用。如果我不需要引用,我不会保留它以使代码混乱。

编辑:  要回答有关正在进行垃圾回收的线程的编辑,在线程运行时不会发生这种情况。 CLR保留对每个正在运行的线程的引用。不会收集表示该线程的对象。


11
2017-12-24 05:00



很酷,在这个特殊情况下并不重要,但可能会在它退出后收集,对吧? - devios1
是。对线程对象的引用与实际执行线程一起放在堆栈上。一旦实际线程完成,那么如果我正确地回想起我的Richter,就不会引用线程对象。我在CLR中通过C#或C#在Nutshell中读到了它。两本好书。 - Jason Jackson


这取决于。在用户可以取消线程操作的情况下,应该保留引用,以便在用户需要时取消线程。在其他情况下,可能不需要存储引用。


2
2017-12-24 04:45



取消不是必需的 - 它是后台(同步)操作,但我希望它在关机时保持应用程序处于活动状态,以便它可以在退出之前执行最终同步。我正在使用ThreadPool,直到我意识到退出应用程序中止了线程。 - devios1


我在生产代码中有很多案例,这样做是合适的。所以,是的,在不保留引用的情况下在一行中定义和启动一个线程就可以了。我认为保留一个参考“以防万一”你后来重新设计并需要它是失败的原则,创造最简单的工作。

并且,对于第二部分,它在运行时不会是GC;线程是根级对象,GCtor将从中查找引用。一旦任何正在运行的线程(包括您在其上启动的线程)无法访问线程实例,它将只是GCd。

并注意泄漏创建但从未启动的Thread实例。我相信他们会永远存在。


1
2017-12-24 06:09





问一个问题“这个帖子多久可以启动一次?”可能会很好。是每个应用程序,每个类,每个对象的实例,还是每个方法的调用?这可能会告诉您存储它的变量(如果有的话)。


0
2017-12-24 04:55



基本上我会按照约5分钟的时间表执行该行,并担心它是否会泄漏,或者线程是否正常运行。 - devios1
线程是否泄漏(或者更糟,简单地循环到无穷大)取决于它正在执行的代码。是否可以分离出一个非线程取决于它将运行的代码。 - Chris


是的,您应该,因为您永远不知道以后何时需要更改代码以便以某种方式处理该线程。那个,把太多的东西放在一条线上就像那样丑陋。

说实话,你可以按照自己的方式去做,所以答案真的归结为代码风格偏好。


0
2017-12-24 05:01





除了上面发布的“m3rLinEz”之外,另一个缺点是如果你的线程中发生任何异常,甚至很难检测到这种情况。


0
2017-12-24 05:38