将服务与计时器同步

时间:2010-09-24 20:51:09

标签: c# service synchronization timing

我正在尝试在c#中编写一个服务,该服务应该在给定日期的给定间隔(超时)下运行。如果日期是将来,则服务应等待开始,直到达到日期时间。

示例:

  • 如果我将超时设置为从21:00:00开始1小时我希望程序每小时运行一次

  • 如果我将超时时间从3999.01.01 21:00:00设置为1小时我想让程序到日期,然后每小时运行一次

我已经通过以下代码实现了这一点,但它存在一些问题!

  1. 当我安装服务(使用installutil)时,由于'Thread.Sleep()',服务被标记为开始。此服务似乎已挂起,并且在安装之前一直在“安装”。

  2. 'ServiceTimer_Tick()'中的代码可能需要比预期超时更长的时间。如果发生这种情况,如何防止定时器堆栈增加?

  3. 我想到的替代方案:

    • 首次使用'timeout.Interval',然后重置后续调用,但感觉不对。

    • 我还考虑放弃整个服务理念并将其编译为可执行文件并设置计划任务。

    缩短的例子:

    public Service()
    {
        _timeout = new TimeSpan(0,1,0,0);
        _timer = new System.Timers.Timer();
        _timer.Interval = _timeout.TotalMilliseconds;
        _timer.Elapsed += new ElapsedEventHandler(ServiceTimer_Tick);            
    }
    
    private void ServiceTimer_Tick(object sender, System.Timers.ElapsedEventArgs e)
    {            
        lock (_obj)  
        { 
            // Stuff that could take a lot of time
        }
    }
    
    public static void Main()
    {
        Run(new Service());
    }
    
    protected override void OnStart(string[] args)
    {
        long current = DateTime.Now.Ticks;
        long start = new DateTime(2010,9,15,21,0,0).Ticks;
        long timeout = _timeout.Ticks;
        long sleep;
    
        if (current > start)
            sleep = timeout - ((current % timeout)) + (start % timeout);
        else
            sleep = start - current;
    
        Thread.Sleep(new TimeSpan(sleep));
    
        _timer.AutoReset = true;
        _timer.Enabled = true;
        _timer.Start();
    }
    

3 个答案:

答案 0 :(得分:2)

您可以使用System.Threading.Timer。它支持dueTimeperiod,这正是您所需要的。

答案 1 :(得分:2)

使用System.Threading.Timer可以更轻松。您可以告诉它在第一次打勾之前等待多长时间,然后再确定在此之后打勾的频率。

所以,如果你想在开始前等待2天,然后每小时做一次,你会写:

Timer MyTimer = new Timer(TimerCallback, null, TimeSpan.FromHours(48), TimeSpan.FromHours(1));

也就是说,如果这只需要每小时运行一次,那么听起来你真正想要的是一个可执行文件,然后你可以使用Windows任务计划程序安排。

答案 2 :(得分:1)

您必须将计时器逻辑移动到您从OnStart例程生成的单独线程。那么你的逻辑不会干扰SCM,服务就会正常启动。

编辑:只是为了详细说明 - 对于这个任务,我不认为计时器工作得很好,因为你没有考虑时钟校正,这可能导致歪斜(如果用户手动改变时钟时间甚至不正确)。这就是为什么比较小间隔的时钟时间是首选。

该线程的Run例程可能如下所示:

    public void run()
    {
        while (processing)
        {
            //initiate action on every full hour
            if (DateTime.Now.Second == 0 && DateTime.Now.Minute == 0)
            {
                //Do something here
                DoSomething();
                //Make sure we sleep long enough that datetime.now.second > 0
                Thread.Sleep(1000);
            }
            Thread.Sleep(100);
        }
    }