开发者

System.Timers.Timer interval resetting causing restart

I'm running into a problem with the System.Timers.Timer in a windows service. I basically set the timer up in a base polling service class with the following code:

_serviceTimer.Elapsed += OnElapsedTime;
_serviceTimer.Interval = ServiceTimerInterval.TotalMilliseconds;
_serviceTi开发者_如何学Pythonmer.AutoReset = false;
_serviceTimer.Enabled = true;

When the OnElapsedTime fires, I want to disable the timer and set the interval to a different value based on a lookup. The problem is when I change the interval it actually restarts the timer. This strange behavior is mentioned in the msndn docs with:

Note: If Enabled and AutoReset are both set to false, and the timer has previously been enabled, setting the Interval property causes the Elapsed event to be raised once, as if the Enabled property had been set to true. To set the interval without raising the event, you can temporarily set the AutoReset property to true. Timer.Interval

In the onelapsed event I have this:

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

The problem is the interval change still begins the timer countdown and eventually fires off the event even though I set the autoreset to true prior to changing the interval. The enabled remains false at all times, but the event still fires. I'm not sure if I'm misinterpreting the msdn docs about the correct way to do this. Can anyone help me out?


I believe this has to do with the EventHandler being called from a different thread than the code currently setting Enabled to false.

According to MSDN Doc:

The signal to raise the Elapsed event is always queued for execution on a ThreadPool thread, so the event-handling method might run on one thread at the same time that a call to the Stop method runs on another thread. This might result in the Elapsed event being raised after the Stop method is called. The code example in the next section shows one way to work around this race condition.

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


Can you set a boolean m_SetEnabled = true in your existing OnElapsedTime event and then add if(m_SetEnabled) { m_SetEnabled = false; return; } to just ignore the single event that gets fired.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜