2011-03-29 57 views
3

我正在与在Windows服务的System.Timers.Timer一个问题。我基本上用下面的代码设置定时器了在碱轮询服务类: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

在onelapsed事件中,我有这样的:

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

的问题是间隔变化仍然开始倒计时,最终触发中断,即使我要改变自动复位设置为true之前的事件间隔。启用的时间始终保持为假,但事件仍然发生。我不确定我是否误解了msdn文档中有关正确的方法。谁能帮我吗?

+0

是啊,这是一个悲惨的类。这就是为什么存在System.Threading.Timer。 – 2011-03-29 22:18:47

+0

是的,它确实似乎有限制。我想我会使用下面的快捷方式,然后在我有机会时切换它。 – gleasonomicon 2011-03-30 15:01:34

回答

1

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

1

我相信这与EventHandler被调用的线程不同,而不是目前设置的代码Enabledfalse

根据MSDN Doc

提高Elapsed事件 总是排队上 线程池线程执行的信号,所以 事件处理方法可能会在同一时间上一个 线程上运行这对 Stop方法上的另一个 线程上运行的呼叫。这可能导致 停止方法被调用后引发Elapsed事件。在下一节中的代码 示例显示了解决这个种族 条件一个 方式。

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