2011-03-29 68 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; } 
    } 
}