c# - System.Timers.Timer 间隔重置导致重启

标签 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

问题是间隔更改仍然会开始计时器倒计时并最终触发事件,即使我在更改间隔之前将 autoreset 设置为 true。 enabled 始终保持为 false,但事件仍会触发。我不确定我是否误解了有关执行此操作的正确方法的 msdn 文档。谁能帮帮我?

最佳答案

我相信这与 EventHandler 从不同的线程调用有关,而不是当前将 Enabled 设置为 false 的代码。

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

关于c# - System.Timers.Timer 间隔重置导致重启,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5478442/

相关文章:

javascript - 如何每 90 秒触发一次 Azure 计时器功能?

c# - 使用 AutoMapper 映射类数组

c# - ASP.NET Core Identity session 过期早于配置发生的时间

c# - Quartz.net 使用不同的 JobKey 和 JobData 运行 1 个作业实例

javascript - 在 aspx 页面上仅运行一次 javascript 计时器

ios - 如何在时间后停止 DispatchGroup? iOS

c# - 在插入命令asp中获取ID并在c#后面的代码中使用它

c# - 创建 FileStream.Open c# 的接口(interface)

c++ - 如果我使用 scanf 程序终止

iphone - 如何在 Objective-C 中编写计时器?