我在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文档关于正确的方法来做到这一点。任何人都可以帮助我吗?
答案 0 :(得分:2)
我认为这与从与当前设置Enabled
到false
的代码不同的线程调用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; }
以忽略被触发的单个事件。