Windows Forms中的线程已经以代码0退出。

4
我在我的Windows Forms中退出线程遇到了问题。
我有一个经典的Windows Forms应用程序正在运行。我需要每隔一段时间执行一些操作,因此我添加了:
TimerCallback timerDelegate = new TimerCallback(this.TryDoSomething);
int period = 10 * 1000; // to miliseconds
System.Threading.Timer stateTimer = new System.Threading.Timer(timerDelegate, null, period, period);

DoSomething 方法只被少数线程(主线程和计时器)调用,因此我这样封装它:

private void TryDoSomething(object o)
        {
            lock (tryDoSomethingMutex)
            {
                if (this.dataGridView1.InvokeRequired)
                {
                    RefreshCallback d = new RefreshCallback(DoSomething);
                    this.Invoke(d, new object[] { o });
                }
                else
                {
                    this.DoSomething(o);
                } 
            }
        }

一切都运行正常,直到我的计时器线程突然退出并显示消息:
The thread 0x2798 has exited with code 0 (0x0).

相同的问题也发生在我的FileSystemWatcher上,它也调用DoSomething方法。这两个事件是独立的,并且在随机时间退出(至少我没有找到任何规律)。
是什么导致了这种情况,我该如何防止它?

这并不是一个错误,它只是表明线程已经完成了它的执行。 - Prabhu Murthy
直到你的时间线程退出?那么它不是意味着要退出吗?难道不是你设置了dueTime吗? - Chibueze Opata
那就是问题所在 - 我不知道。计时器被设置为每隔一段时间执行某些操作,但突然在随机的时间退出(但没有任何错误信息)。 - Peter
2个回答

4
如果你不保留计时器对象的引用,它将被垃圾回收。
从您发布的代码来看,似乎您没有保持对该引用的控制。您需要在包含类中将其作为字段而不是局部变量。
如果您在长时间运行的方法开始时声明计时器并且后面没有引用它,那么计时器也可能会被垃圾回收。
您可以通过在方法末尾附近添加“GC.KeepAlive(timer);”来解决特定的问题如此描述

当然,这是正确的答案,谢谢!现在当我想起来时,它似乎很明显。误导我的是通常需要花费一分钟左右的时间才能退出线程,即使声明它的方法早已结束了。所以垃圾回收器需要大约一分钟(有时甚至需要两分钟或更长时间)才能发现它是垃圾并应该被处理?为什么要这么久? - Peter
1
垃圾回收器倾向于仅在内存不足时才运行,以减少开销;我认为这就是为什么它需要那么长时间的原因。 - Matthew Watson
那很有意义。谢谢 :) - Peter
1
要完全准确,我应该说“第二代垃圾回收往往不会经常运行”。第0代会经常运行,但计时器可能已经存活到第2代。 - Matthew Watson

3

看起来定时器正在被垃圾回收。将其作为表单的实例变量,以便您可以保留引用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接