执行时间超过span时的计时器行为?

时间:2012-01-18 20:39:43

标签: c# .net windows-services timer

我正在编写Windows服务,它会每隔几分钟处理一次“某事”。

以下是一些代码:

public Service()
        {
            this.InitializeComponent();
            this.ServiceName = Name;
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;

            this.eventLog.Source = Name;

            // initialize timer
            this.timer.Elapsed += this.TimerElapsed;
        }

        private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information);

            if (this.processor.PrepareToRun())
            {
                this.processor.Run();
            }
        }

我想知道如果this.processor.Run()需要很长时间并且下一个TimerElapsed事件会被提升会发生什么?它会跳过吗?完成后会等待并尽快运行吗?我应该考虑这些场景和代码吗?

我正在使用System.Timers.Timer

修改

private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information);

            try
            {
                this.timer.Stop();
                if (this.processor.PrepareToRun())
                {
                    this.processor.Run();
                }
            }
            catch (Exception ex)
            {
                LoggingAndNotifications.LogAndNotify(ex);

            }
            finally
            {
                this.timer.Start();
            }
        }

编辑2

public Service()
        {
            this.InitializeComponent();
            this.ServiceName = Name;
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;

            this.eventLog.Source = Name;

            // initialize timer
            this.timer.AutoReset = false;
            this.timer.Elapsed += this.TimerElapsed;
        }

        private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            eventLog.WriteEntry("Starting syncronization...", EventLogEntryType.Information);

            try
            {
                if (this.processor.PrepareToRun())
                {
                    this.processor.Run();
                }
            }
            catch (Exception ex)
            {
                LoggingAndNotifications.LogAndNotify(ex);
                throw;
            }
            finally
            {
                this.timer.Start();
            }
        }

6 个答案:

答案 0 :(得分:14)

它会在另一个主题上再次调用它。

根据您要执行的操作的性质:

  1. 忽略这一点,如果调用的代码对多个同时调用是安全的,那么这可能没问题。当然,你必须知道它没关系。
  2. 锁定定时器触发的操作。请注意,您最终可能会有许多待处理操作的队列,这些操作非常坏。
  3. 锁定定时器触发的操作,尝试获取超时为零的锁定,如果失败则跳过它 - 从最后一次开始仍有一个线程。
  4. 将计时器作为一次性计时器,在每次通话结束时重新启动。

答案 1 :(得分:4)

如果我不希望后续的计时器激活在完成之前再次执行该方法,我会使用以下内容:

private void TimerFired(object sender, System.Timers.ElapsedEventArgs e) {
    // only execute the code within this method if we are able to
    // get a lock. This will ensure that any Timer firings will be
    // ignored that occur while we're already doing work (OnTimer) 
    if (Monitor.TryEnter(lockObj)) {
        try {
            // do work here
        } finally {
            Monitor.Exit(lockObj);
        }
    }
}

否则,如果该方法的持续时间可能长于计时器间隔,则该方法可能会在第一个完成之前在另一个线程上开始执行。

答案 2 :(得分:3)

您可以看到此示例应用会发生什么:

class Program
{
    static void Main(string[] args)
    {
        System.Timers.Timer timer = new System.Timers.Timer(2000);
        timer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedObject);
        timer.Start();

        while (true)
        {
        }

    }

    static void OnTimedObject(object source, ElapsedEventArgs e)
    {
        Console.WriteLine("entered");
        Thread.Sleep(3000);
        Console.WriteLine("exited");

    }
}

在“退出”首次出现之前,您会看到两个“已输入”的字符串显示出来。它会继续下去。所以线程不会互相踩到。

(顺便说一句,我不是在提倡无限循环。:))

答案 3 :(得分:2)

当引发计时器事件时,计划在线程池上执行计时器代码。最有可能它将在另一个线程中执行,但它取决于不同的因素(处理器数,线程利用率等)。然而它与计时器没有任何关系 - 它是线程池的职责。

我个人从不使用计时器间隔。我设置计时器运行一次,在我的代码执行后再次设置它。因此,我确保代码仅在单线程中执行。

答案 4 :(得分:0)

我这样做是为了处理这种情况。当然,您需要针对多线程操作等特殊情况进行调整。

    public Service()
    {
        bool _IsProcessRunning = false;
        this.InitializeComponent();
        this.ServiceName = Name;
        this.CanPauseAndContinue = true;
        this.CanShutdown = true;

        this.eventLog.Source = Name;

        // initialize timer
        this.timer.Elapsed += this.TimerElapsed;
    }

    private void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        if(!_IsProcessRunning)
        {
            DoSomething();
        }           
    }

    private void DoSomething()
    {
        try
        {
             _IsProcessRunning = true;

             // Do our stuff here
        }
        catch(Exception Ex)
        {               
        }
        finally
        {
             _IsProcessRunning = false;
        }
    }

答案 5 :(得分:0)

执行时间超过span时的计时器行为?

当任务执行时间超过计时器时间跨度时。 TimerElapsed事件将被提升为一个新的线程。它不会被跳过。多线程实现到System.Timers.Timer