【问题标题】:Timer Does Not Fire Before Application Ends in C#在 C# 中的应用程序结束之前计时器不会触发
【发布时间】:2016-01-23 01:59:49
【问题描述】:

我在 C# 中有一个简单的控制台应用程序,它创建了一个计时器来将文本写入控制台。然后等待用户按键。

如果用户在五秒内按下某个键,则应用程序结束,并且计时器永远不会触发。如果用户没有按任何键,则计时器按预期触发。

为什么计时器创建的线程不能阻止应用程序终止?即使用户按键,我应该如何确保应用程序继续运行?

static void Main(string[] args)
    {
        System.Timers.Timer timer = new System.Timers.Timer(5000);
        timer.Interval = 5000; // 5 seconds
        timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
        timer.Enabled = true;
        timer.AutoReset = true;
        timer.Start();
        Console.ReadKey();
    }

    public static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        Console.WriteLine("Timer Fired.");
    }

【问题讨论】:

    标签: c# multithreading timer


    【解决方案1】:

    要让定时器消息始终写出,您可以让主线程等待在定时器触发后发出的reset event

        static ManualResetEvent timerFired = new ManualResetEvent(false);
    
        static void Main(string[] args)
        {
            System.Timers.Timer timer = new System.Timers.Timer(5000);
            timer.Interval = 5000; // 5 seconds
            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
            timer.Enabled = true;
            timer.AutoReset = true;
            timer.Start();
            Console.ReadKey();
    
            // This call will return only after timerFired.Set() is
            // called.  So, if the user hits a key before the timer is
            // fired, this will block for a little bit, until the timer fires.  
            // Otherwise, it will return immediately
            timerFired.WaitOne();
        }
    
        public static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            Console.WriteLine("Timer Fired.");
            timerFired.Set();
        }
    

    至于另一个问题,为什么它不阻止应用程序退出,我会刺一下。正在从后台线程调用 timer_Elapsed()。根据 MSDN,后台线程不会让执行环境保持运行。这里有一个nice discussion

    ThreadPool 线程是后台线程,MSDN Timer 文档表明 Timer 的 Elapsed event 是在 ThreadPool 线程上引发的,因此应用程序不会等待它,因为它不是前台线程。

    【讨论】:

    • 很好的答案,只有 ThreadPool 线程不是后台线程,任何 CLR 管理的线程(即System.Threading.Thread 的实例)都可以标记为后台或前台,无论其实例是否被池化.
    • @BorisB。感谢您的评论。让我们试着澄清答案。虽然我们可以将 ThreadPool 线程从后台更改为前台,但默认情况下将它们视为后台线程是否安全,还是不确定?
    猜你喜欢
    • 1970-01-01
    • 2017-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多