C# - Timer的实例什么时候会被杀死?

时间:2011-05-27 23:28:18

标签: c#

鉴于以下代码,计时器将每隔一秒触发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();
    }
}

5 个答案:

答案 0 :(得分:4)

回答1

现在只有在程序退出时才会停止计时器。它并不是真的坐在那里使用后台线程,但是当发生计时器事件时,将通过一个 后台线程的ThreadPool线程调用回调。

回答2

停止计时器非常简单:

t.Change(Timeout.Infinite, Timeout.Infinite);

- 或 -

t.Dispose();

前者允许您通过另一次调用Timer重新启动Change,因为后者将完全清除Timer

有关其行为的更多详细信息,建议您阅读its MSDN documentationTimer课程的备注部分。例如,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()它。

请注意,如果您在方法中启动计时器并且不保留对它的引用,则在收集垃圾时它将被停止。