C#——Timer的实例何时会被终止
本文关键字:终止 何时会 Timer 实例 | 更新日期: 2023-09-27 17:57:55
给定以下代码,计时器将每隔一秒钟触发一次PrintTimer函数,直到用户按键。
问题1>计时器何时停止?计时器在默认情况下是后台线程吗?因此它将在前台线程终止后被终止。
问题2>如何以编程方式停止调用线程中的计时器?
class Program
{
// continue to call this function until the user presses a
// key to terminate the application
static void PrintTime(object state)
{
Console.WriteLine("Time is: {0}",
DateTime.Now.ToLongTimeString());
}
static void Main(string[] args)
{
TimerCallback timeCB = new TimerCallback(PrintTime);
System.Threading.Timer t = new Timer(
timeCB,
null,
0,
1000);
Console.WriteLine("Hit key to terminate...");
Console.ReadLine();
}
}
答案1
现在,只有当程序退出时,计时器才会停止。它并不是真正使用后台线程,但当计时器事件发生时,回调将通过ThreadPool线程调用,是后台线程。
答案2
停止计时器很简单:
t.Change(Timeout.Infinite, Timeout.Infinite);
--或--
t.Dispose();
前者允许您通过另一个对Change
的调用重新启动Timer
,后者将完全清除Timer
。
有关其行为的更多详细信息,我建议阅读MSDN文档中Timer
类的"备注"部分。例如,Dispose
有一些棘手的时间安排,因为Timer
可能已经将通知回调排队到线程池,即使在调用Dispose
之后,从技术上讲也可以接收到该通知回调。
计时器将通过finzalizer运行进行清理。这就是它变成garabage的时候,它实际上因发布模式和调试模式而异。
下面是一个我们可以使用WeakReference运行的测试:
internal class Program
{
// continue to call this function until the user presses a
// key to terminate the application
private static void PrintTime(object state)
{
Console.WriteLine("Time is: {0}",
DateTime.Now.ToLongTimeString());
}
private static void Main(string[] args)
{
TimerCallback timeCB = new TimerCallback(PrintTime);
Timer t = new Timer(
timeCB,
null,
0,
1000);
WeakReference wk = new WeakReference(t);
PrintStatus(wk);
Console.WriteLine("Hit key to terminate...");
Console.ReadLine();
t = null;
PrintStatus(wk);
}
private static void PrintStatus(WeakReference wk)
{
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Is timer alive? " + wk.IsAlive);
}
}
Timer
是一次性的,因此您应该/必须对其调用Dispose
。如果您想重用它,也可以调用Stop
,但Timer类中存在一个带有定期回调的错误,因此建议只处理它并从新计时器开始。
在你发布的代码中会发生的事情是,定时器的终结器将(从技术上讲可能)被调用,这将杀死它。
在您的应用程序中,它永远不会停止,直到您退出应用程序。
要用程序停止它,这取决于你使用的计时器。
System.Timers.Timer
System.Threading.Timer
如果是第一个,则可以调用Stop方法。如果是第二个,你必须处理()它。
请注意,如果您在一个方法中启动计时器,并且不保留对它的引用,那么当它被垃圾收集时,它将被停止。
关于问题2,请参阅Timer.Enabled属性和Timer.Close()方法
更新:我想为了完整起见,我还应该提到Timer.Stop()方法(它将Enabled设置为false)
更新:每个选项应该在什么时候使用?
广义上讲,有两种情况:要么你正在取消计时器,再也不打算使用它,要么你正在暂停计时器,但计划在某个时候恢复它(或者至少希望选项能够恢复它)。
如果您要取消计时器,那么Dispose/Close就是您要采取的路线。至少您应该调用Dispose,因为当一个行为良好的程序完成一个实现IDisposable的对象时,它应该这样做。
也就是说,当一个对象同时实现IDisposable和Close方法时,我认为更好的方法是调用Close,因为Close可能做的不仅仅是释放资源。例如,它可能会刷新缓冲区或做一些其他特定于对象的事情。可以期望Close方法调用Dispose。理想情况下,Close的文档会明确说明它调用Dispose(但Timer::Close的文件没有说明它调用了Dispose)。
要临时暂停和恢复计时器,可以将Enabled属性设置为false,然后再次设置为true。或者,你可以调用Stop(),然后调用Start()来恢复它。
我想有人可能会说,"停止"answers"启动"的可读性稍高,效率可能稍低(因为它们依次设置为"启用")。