定时器仅在调试模式下工作

Posted

技术标签:

【中文标题】定时器仅在调试模式下工作【英文标题】:Timer only works in debug mode 【发布时间】:2014-08-28 10:39:11 【问题描述】:

我有一个带有以下主程序的控制台应用程序:

    static void Main(string[] args)
    
        var timer = new System.Threading.Timer(
         e =>
            
            //some code here
        ,
        null,
        TimeSpan.Zero,
        TimeSpan.FromMinutes(1));


        var backupTimer = new System.Threading.Timer(
         e =>
         
             //some code here

         ,
        null,
        TimeSpan.Zero,
        TimeSpan.FromHours(24));

        Console.ReadLine();

    

问题在于,在调试模式下它工作正常,并在正确的时间段内调用两个计时器中的方法,如果在控制台中输入某些内容,程序将结束工作(Console.ReadLine() 就是为了那个),但是当我运行程序时在 Release 模式下,两个定时器只调用一次(第一次),然后程序只是等到我输入一些东西。

如何解决这个问题,以便我可以编译一个正常工作的独立程序?

【问题讨论】:

看起来定时器被 GC 抑制了。 您需要保留对计时器的引用作为字段。否则,GC 会吃掉它。 那为什么在调试模式下能正常工作呢? 参考here和here @AdrianoRepetti 不,JIT 很聪明,可以判断是否不再使用本地人。如果没有,jit 会告诉 GC 他们可以被 GC'd。请参考我上面的评论,汉斯解释得很好.. 【参考方案1】:

正如@SriramSakthivel 建议的那样,您必须将对计时器的引用保留为一个字段,否则垃圾收集器会吃掉您的计时器。 所以这里是解决方案:

    private static System.Threading.Timer timer;
    private static System.Threading.Timer backupTimer;

    static void Main(string[] args)
    

        timer = new System.Threading.Timer(
         e =>
            
            //something
        ,
        null,
        TimeSpan.Zero,
        TimeSpan.FromMinutes(1));


        backupTimer = new System.Threading.Timer(
         e =>
         
             //something

         ,
        null,
        TimeSpan.Zero,
        TimeSpan.FromHours(24));

        Console.ReadLine();

    

【讨论】:

【参考方案2】:

希望以下解决方案有所帮助!

问题:

通过显示当前时钟时间,以下代码始终按预期工作。

 class Program
 
        static void TimerProcedure(object param)
        
            Console.Clear();
            Console.WriteLine(DateTime.Now.TimeOfDay);

            GC.Collect();

        

        static void Main(string[] args)
        
            Console.Title = "Desktop Clock";
            Console.SetWindowSize(20, 2);
            Timer timer = new Timer(TimerProcedure, null,
                TimeSpan.Zero, TimeSpan.FromSeconds(1));
            Console.ReadLine();
        
    

但是,如果您在发布模式下运行相同的代码,它只会在第一次显示当前时间,但之后不会更新。

解决方案

通过添加 GC.KeepAlive(object) 的简单调整将使其在发布模式下也可以正常工作。参考下面的代码。

class Program
    
        static void TimerProcedure(object param)
        
            Console.Clear();
            Console.WriteLine(DateTime.Now.TimeOfDay);
            #region Hidden
            GC.Collect();
            #endregion
        

        static void Main(string[] args)
        
            Console.Title = "Desktop Clock";
            Console.SetWindowSize(20, 2);
            Timer timer = new Timer(TimerProcedure, null,
                TimeSpan.Zero, TimeSpan.FromSeconds(1));
            Console.ReadLine();
            GC.KeepAlive(timer);
        
    

替代解决方案:正在使计时器成为类级别的静态变量

【讨论】:

以上是关于定时器仅在调试模式下工作的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 程序仅在 Visual Studio 2013 中的调试模式下工作

父 NSManagedObjectContext 在子保存后没有变化,但仅在发布模式下(在调试模式下工作)

无密码 SSH 仅在调试模式下工作

SSIS 脚本组件 - 仅在调试模式下工作

使用 Spotify API 的 Android 应用程序仅在调试模式下工作

用 Python 编写的 Windows 服务仅在调试模式下工作