【问题标题】:Winservice - Timer: Same task being executed parallelWinservice - 计时器:并行执行相同的任务
【发布时间】:2014-08-22 02:45:52
【问题描述】:

我制作了一个窗口服务,它在每个之后执行一个操作。我们将定时器声明如下:

using System.Timers;

....

Int32 myInterval = 60000 * (Convert.ToInt32(ConfigurationManager.AppSettings["lpInterval"].ToString()));
_myTimer = new Timer();
_myTimer.Interval = myInterval;
_myTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);

    //Timer-Tick
private void TimerElapsed(object source, ElapsedEventArgs e)
{ PerformAction(); }

注意到了什么: 如果PerformAction() 比我的interval 花费的时间更长(由于WCF 服务或服务器问题),则启动并执行PerformAction 的新'instance'。所以PerformAction 彼此运行两次(和parallel)。

这是什么原因?为什么之前的PerformAction 没有被取消?方法PerformAction是否正在执行Async

我找到了解决方法,但我就是不明白这种行为...

【问题讨论】:

    标签: c# windows-services system.timers.timer


    【解决方案1】:

    在您运行操作之前停止计时器,然后在执行操作后再次启动计时器

    private void TimerElapsed(object source, ElapsedEventArgs e)
    { 
        _myTimer.Stop();
        PerformAction();
        _myTimer.Start();
    }
    

    系统定时器

    http://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed(v=vs.110).aspx

    在 ThreadPool 线程上引发 Elapsed 事件。如果 Elapsed 事件的处理持续时间超过 Interval,则该事件可能会在另一个 ThreadPool 线程上再次引发。在这种情况下,事件处理程序应该是可重入的。

    在调用 Dispose 或 Stop 方法之后或在 Enabled 属性设置为 false 之后可能会发生 Elapsed 事件,因为引发 Elapsed 事件的信号总是排队等待在线程池线程上执行。解决这种竞争条件的一种方法是设置一个标志,告诉 Elapsed 事件的事件处理程序忽略后续事件。

    【讨论】:

    • 我现在知道了。但我不是在寻找解决方案。我正在寻找上一个动作没有被取消的原因。
    • 它在 ThreadPool 线程上产生,因此它不会取消它只是产生另一个线程来运行。
    • 但这不只适用于 System.Threading.Timers... 类型的对象吗?
    【解决方案2】:

    这只是计时器的设计决定。它有许多可能的解决方案,从并行触发事件、将处理程序排队直到前一个处理程序完成后立即到完全跳过该特定事件。设计师选择了该选项。他们可以很容易地选择另一个,就像某些其他计时器的设计者所做的那样。

    至于为什么不取消,非合作取消代码是非常危险且极易出错的,并且滴答处理程序的实现通常不会觉得需要实现合作取消(他们可以如果他们真的想这样做,请使用现有的实现)所以这不是一个实际的选择。

    【讨论】:

      猜你喜欢
      • 2014-09-14
      • 1970-01-01
      • 2014-03-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多