2011-10-04 67 views
3

我正在尝试编写无限期运行的Windows服务。用于Linux的Windows窗体和后台程序看起来并不算太糟糕,但也许我在Windows服务中只是非常无能。不像其他一些睡眠或计时器相关的问题,我已经在这里挖过,醒来或睡觉的时间可以是一个固定的时间间隔,但并不总是这样。程序从某些数据文件中读取数据,这些数据文件可能会指示它更改自己的时间表,并且必须在下一次起床时生效。这似乎很容易,因为一个控制台程序和行为完全有:C中的可调服务计时器

while (true) 
{ 
    // Calculate next time to run. 
    DateTime nextRun = NextWakeup(); 
    TimeSpan nextTime = nextRun - DateTime.Now; 
    int sleepMs = (int)nextTime.TotalMilliseconds; 
    // Sleep until scheduled time 
    System.Threading.Thread.Sleep(sleepMs); 
    // Do a code cycle of more stuff here... 
} 

然而,当我尝试运行它作为服务的一部分,使其继续活跃在用户注销时,服务管理器固执地拒绝启动它。我得到了可爱的1053错误,“服务没有及时响应启动或控制请求。”

很多答案在这里有关问题的似乎暗示与在休眠线程的所有费用定时器去。如果我做了这样的事情而不是休眠/睡眠组合,我将如何去改变每次运行的计时器间隔?或者这一切都很好,我正在设置我的服务是错误的?

非常感谢提前!

+0

你尝试把简单的代码和运行服务?解决方案可以用错误的方式编译 –

回答

6

的Windows服务通常要到控制请求(后容易启动/停止,也暂停/恢复)在30秒。这意味着如果你睡在OnStart的主线程中,你的服务将返回你引用的错误。

来解决此问题的方法是做一个单独的线程,在那里你可以自由地睡在你所描述的方式线程的工作。只需在服务'OnStart中启动此线程,并且您应该能够在30秒内轻松返回。

顺便说一句,而不是while(true)你应该考虑停止该服务也必须返回有30秒的限制。如果您有一个线程正在休眠,那么在没有任何线程(坏)或提供某种正确退出线程的机制的情况下,服务将无法正常关闭。这正是大多数人采用投票方式的原因。该服务既可以确定其运行时间,也可以确定是否发生停止请求。只要这个投票频率是< 30秒,服务就会一直正常关闭。

+0

@Tuzo:这可能取决于你使用什么Timer,因为我似乎记得它们中至少有三个(在系统中。定时器,system.forms某处,我忘记了第三个地方)。 – Chris

+0

@Chris - 第三个是'System.Threading.Timer'。和义务。链接到比较:http://msdn.microsoft.com/en-us/magazine/cc164015.aspx – Jamiec

+0

啊是的。链接比较的好主意。我应该再看一遍,因为我习惯于使用System.Timers.Timer。 :) – Chris

1

如果你想使用定时器它很容易做到。我会用System.Timers.Timer,改变它的间隔就像mytimer.Inverval = nextTime.Seconds或类似的那样简单。

我会亲自运行没有AutoReset = false的定时器(所以它不会自动重启定时器),然后每当它醒来时它就会运行你的“dowork”,然后在你的dowork结束时,希望它接下来运行,根据需要设置时间间隔,然后再次调用计时器上的开始。

当然在你的服务你的启动方法只设置了第一个定时器运行,然后返回,以便启动是好的和快捷。在关机时,您只需清理计时器(停止并处置等),然后再返回。很好,很干净。

1

我想你可能会寻找这样的事情:

static class ConsoleProgram 
{ 
    static void Main() 
    { 
     ServiceBase[] servicesToRun = new ServiceBase[] { new MyService(config, Logger) }; 
     ServiceBase.Run(servicesToRun); 
    } 
} 



public partial class MyService : ServiceBase 
{ 
    private bool _stopped = true; 

    protected override void OnStart(string[] args) 
    { 
     StartTimer(); 
    } 

    protected override void OnStop() 
    { 
     StopTimer(); 
    } 

    public void StartTimer() 
    { 
     _stopped = false; 
     Timer t = new Timer(TimerProc); 
     // Calculate your desired interval here. 
     t.Change(_config.Interval, new TimeSpan(0, 0, 0, 0, -1)); 
    } 

    public void StopTimer() 
    { 
     _stopped = true; 
    } 

    private void TimerProc(object state) 
    { 
     // The state object is the Timer object. 
     Timer t = (Timer) state; 
     t.Dispose(); 

     ThreadPool.QueueUserWorkItem(DoWork); 

     if (!_stopped) { 
      StartTimer(); 
     } 
    } 

} 
+0

您可能想明确指出哪个Timer类是。 :) – Chris