在特定时间C#(Windows服务)每天执行方法的代码失败

我有这个代码每天凌晨5点执行Windows服务的方法:

编辑:

MyService ws = new MyService (); protected override void OnStart(string[] args) { if (serviceHost != null) { serviceHost.Close(); } serviceHost = new ServiceHost(typeof(MyService)); serviceHost.Open(); double TimeOfExecution = 5; DateTime now = DateTime.Now; DateTime today5am = now.Date.AddHours(TimeOfExecution); DateTime next5am = now <= today5am ? today5am : today5am.AddDays(1); System.Threading.TimerCallback callback = new System.Threading.TimerCallback(ws.MethodToExecute()); var timer1 = new System.Threading.Timer(callback, null, next5am - DateTime.Now, TimeSpan.FromHours(24)); } 

我希望服务在下一个5点执行,之后每24小时执行一次。

方法MethodToExecute()确实在当天5点(或其他一些指定的时间)执行,但第二天它无法执行。 此外,似乎我第一次执行它并不重要,但似乎服务在一段时间后进入睡眠并且不执行,所以如果5点钟到达不是在当天,但是第二天,它将无法执行。

有谁知道什么可能是错的?

GC将收集您的timer因为在OnStart方法之后您没有任何对它的引用。

你只是将它作为局部变量。 我希望你知道一旦JIT说它们不再用在代码中,局部变量就有资格进行垃圾收集。

修复:只需将timer存储在变量实例中,就完成了。

 private System.Threading.Timer my5AmTimer = null; protected override void OnStart(string[] args) { //All other code.. this.my5AmTimer = new System.Threading.Timer(callback, null, next5am - DateTime.Now, TimeSpan.FromHours(24)); } 
 var timer1 = new System.Threading.Timer(...); 

定时器是棘手的对象。 当它们不再被引用时,它们就像任何.NET对象一样受垃圾收集的影响。 这个语句的语法足以知道何时发生这种情况,你对var的使用表明“timer1”是方法的局部变量 。 换句话说,在方法返回后创建的Timer对象没有任何引用。

那么,当没有引用时,究竟是什么让Timer保持活跃并且滴答作响呢? 你发现:什么都没有。 您的计时器是否实际打勾是一个废话。 如果你的程序继续运行其他事情,那么它会触发gen#0集合,计时器将消失。 永远不会打勾。 如果你的程序没有,那么它将存活足够长的时间到达凌晨5点。

必须将对象引用存储在一个变量中,以确保它能够存活足够长的时间。 那应该是一个静态变量。

或者使用System.Timers.Timer。 它的行为很像System.Threading.Timer,但具有更好的生存技能。 只要它具有Elapsed事件处理程序并且已启用,它就可以保证保持活动状态。

请阅读精细手册 :

注意

只要您使用Timer,就必须保留对它的引用。 与任何托管对象一样,当没有对它的引用时,Timer会进行垃圾回收。 Timer仍然处于活动状态的事实不会阻止它被收集。

请参考它:

 MyService ws = new MyService (); System.Threading.Timer timer; protected override void OnStart(string[] args) { ... if (timer1 != null) timer1.Dispose(); timer1 = new System.Threading.Timer(callback, null, next5am - DateTime.Now, TimeSpan.FromHours(24)); } 

另一种选择可能是告诉GarbageCollector保持局部变量的活动:

 GC.KeepAlive(timer1);