鉴于以下代码,计时器将每隔一秒触发PrintTimer函数,直到用户按下某个键。
问题1 >什么时候Timer会停止? 默认情况下,Timer是一个后台线程,因此在前台线程终止后它将被终止。
问题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();
}
}
答案 0 :(得分:4)
回答1
现在只有在程序退出时才会停止计时器。它并不是真的坐在那里使用后台线程,但是当发生计时器事件时,将通过一个 后台线程的ThreadPool线程调用回调。
回答2
停止计时器非常简单:
t.Change(Timeout.Infinite, Timeout.Infinite);
- 或 -
t.Dispose();
前者允许您通过另一次调用Timer
重新启动Change
,因为后者将完全清除Timer
。
有关其行为的更多详细信息,建议您阅读its MSDN documentation中Timer
课程的备注部分。例如,Dispose
有一些棘手的时间因为Timer
可能已经排队了一个通知回调到线程池,即使在调用Dispose
之后你也可以在技术上收到它。
答案 1 :(得分:2)
定时器将通过其finzalizer运行进行清理。那就是它成为garabage,实际上与release to debug mode不同。
以下是我们可以使用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);
}
}
答案 2 :(得分:1)
对于问题2,请参阅Timer.Enabled属性和Timer.Close()方法
更新:我想为了完整性我还应该提到Timer.Stop()方法(将Enabled设置为false)
更新:何时应该使用每个选项?
从广义上讲,有两种情况:要么你摆脱了计时器而又从未计划再次使用它,要么就是暂停计时器但计划在某些时候恢复它(或者至少希望能够选择它恢复它)。
如果你正在摆脱计时器,那么Dispose / Close就是要走的路线。至少你应该调用Dispose,因为当完成一个实现IDisposable的对象时,这是一个表现良好的程序。
也就是说,当一个对象实现IDisposable和Close方法时,我认为更好的方法是调用Close,因为Close可能不仅仅是释放资源。例如,它可能会刷新缓冲区或执行其他特定于对象的操作。人们会期望一种Close方法来调用Dispose。理想情况下,Close的文档会明确声明它调用Dispose(但Timer :: Close的文档并没有说它确实如此)。
要暂时暂停和恢复计时器,可以将Enabled属性设置为false,然后再将其设置为true。或者,您可以调用Stop()然后调用Start()来恢复它。手边我没有偏好一种技术而不是另一种技术。
我想有人可能认为Stop and Start稍微更具可读性,可能效率稍差(因为它们反过来设置为Enabled)。
答案 3 :(得分:1)
Timer
是一次性的,因此您应该/必须在其上调用Dispose
。如果你想重用它,你也可以调用Stop
但是Timer类中有一个错误,周期性的回调使得建议只处理它并以新的计时器开始。
你发布的代码中会发生的事情是Timer的终结器(技术上可能会被调用)将会终止它。
答案 4 :(得分:1)
在您的应用程序中,它将永远停止,直到您退出应用程序。
要以编程方式停止它,它取决于您使用的是哪个计时器。
System.Timers.Timer
System.Threading.Timer
如果是第一个,可以调用Stop方法。 如果是第二个,你必须Dispose()它。
请注意,如果您在方法中启动计时器并且不保留对它的引用,则在收集垃圾时它将被停止。