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

时间:2013-11-29 09:20:52

标签: c# timer windows-services

我有这个代码每天早上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点到达而不是当天,但是第二天,它将无法执行。

有没有人知道可能出现什么问题?

4 个答案:

答案 0 :(得分:9)

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));
}

答案 1 :(得分:5)

var timer1 = new System.Threading.Timer(...);

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

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

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

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

答案 2 :(得分:0)

read the fine manual

  

注意

     

只要您使用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));
 }

答案 3 :(得分:0)

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

GC.KeepAlive(timer1);