System.Timers.Timer间隔重置导致重启

时间:2011-03-29 20:21:02

标签: c# timer

我在Windows服务中遇到了System.Timers.Timer的问题。我基本上使用以下代码在基本轮询服务类中设置计时器:

_serviceTimer.Elapsed += OnElapsedTime;
_serviceTimer.Interval = ServiceTimerInterval.TotalMilliseconds;
_serviceTimer.AutoReset = false;
_serviceTimer.Enabled = true;

当OnElapsedTime触发时,我想禁用定时器并根据查找将间隔设置为不同的值。问题是当我更改间隔时它实际重新启动计时器。 msndn文档中提到了这种奇怪的行为:

注意: 如果Enabled和AutoReset都设置为false,并且先前已启用计时器,则设置Interval属性会导致Elapsed事件被提升一次,就好像Enabled属性已设置为true一样。若要设置间隔而不引发事件,可以暂时将AutoReset属性设置为true。 Timer.Interval

在这件事中,我有这个:

_serviceTimer.Enabled = false;
double newIntervalSetting = newSetting;
base._serviceTimer.AutoReset = true;
base._serviceTimer.Interval = newIntervalSetting;
base._serviceTimer.AutoReset = false;
//reenable after processing

问题是间隔更改仍然开始计时器倒计时并最终触发事件,即使我在更改间隔之前将自动复位设置为true。启用时始终为false,但事件仍然会触发。我不确定我是否误解了msdn文档关于正确的方法来做到这一点。任何人都可以帮助我吗?

2 个答案:

答案 0 :(得分:2)

我认为这与从与当前设置Enabledfalse的代码不同的线程调用EventHandler有关。

根据MSDN Doc

  

提升Elapsed事件的信号   总是排队等待执行   ThreadPool线程,所以   事件处理方法可能在一个上运行   线程同时调用一个   Stop方法在另一个方法上运行   线。这可能会导致   经过的事件被提升了   调用Stop方法。代码   下一节中的示例显示了一个   解决这场比赛的方法   条件。

private static void HandleElapsed(object sender, ElapsedEventArgs e)
{
    numEvents += 1;

    // This example assumes that overlapping events can be
    // discarded. That is, if an Elapsed event is raised before 
    // the previous event is finished processing, the second
    // event is ignored. 
    //
    // CompareExchange is used to take control of syncPoint, 
    // and to determine whether the attempt was successful. 
    // CompareExchange attempts to put 1 into syncPoint, but
    // only if the current value of syncPoint is zero 
    // (specified by the third parameter). If another thread
    // has set syncPoint to 1, or if the control thread has
    // set syncPoint to -1, the current event is skipped. 
    // (Normally it would not be necessary to use a local 
    // variable for the return value. A local variable is 
    // used here to determine the reason the event was 
    // skipped.)
    //
    int sync = Interlocked.CompareExchange(ref syncPoint, 1, 0);
    if (sync == 0)
    {
        // No other event was executing.
        // The event handler simulates an amount of work
        // lasting between 50 and 200 milliseconds, so that
        // some events will overlap.
        int delay = timerIntervalBase 
            - timerIntervalDelta / 2 + rand.Next(timerIntervalDelta);
        Thread.Sleep(delay);
        numExecuted += 1;

        // Release control of syncPoint.
        syncPoint = 0;
    }
    else
    {
        if (sync == 1) { numSkipped += 1; } else { numLate += 1; }
    }
}

答案 1 :(得分:1)

您可以在现有的OnElapsedTime事件中设置布尔值m_SetEnabled = true,然后添加if(m_SetEnabled) { m_SetEnabled = false; return; }以忽略被触发的单个事件。