-2

我有以下使用 System.Timers.Timer 的场景。

创建一个 Timer 对象并分配方法

_JobListener.Enabled = false;
_JobListener.Elapsed += (this.JobListener_Elapsed);

在 JobListener_Elapsed 中,我创建了另一个线程来运行一些函数。

JobListener_Elapsed
{
    //stop the timer
    _JobListener.Enabled = false; 

    System.Threading.Thread pollThread = new Thread(JobListener_ElapsedAsync);
    pollThread.Start();

    //join to the main timer thread
    pollThread.Join();

    //restart the timer
    _JobListener.Enabled = true;
}

在 JobListener_ElapsedAsync 中,我记录了计时器启用状态。

private void JobListener_ElapsedAsync()
{
    try{
        log Timer.Enabled
        some other code
    }finally
    {
        _JobListener.Enabled = true; 
    }
}

但是,我可以看到有些时候,它可以看到计时器状态为真,这是错误的。当 JobListener_ElapsedAsync 正在运行时,应停止计时器。

任何的想法?

4

1 回答 1

3

.NET Framework 中有两个主要的计时器类:线程计时器和窗口计时器。

System.Threading.Timer是线程定时器的基础类。这包装了 Windows可等待计时器对象。该Tick事件在ThreadPool. 它不会Tick在再次触发之前检查是否所有前一个处理程序都已返回Tick。计时器应该准时触发 - 它不会延迟。

System.Windows.Forms.Timer包装 Windows SetTimerAPI。该Tick事件在创建计时器的线程上触发。如果那不是 UI 线程,它实际上不会触发。定时器是最低优先级的消息;它们仅由GetMessage/PeekMessage当没有其他消息未处理时生成。因此,它们可能会显着延迟它们应该生成的时间。

System.Timers.Timer包裹System.Threading.Timer。如果您已将其SynchronizingObject属性设置为某个值,则当底层计时器触发时,它将用于ISynchronizeInvoke.Invoke进入该对象的线程(类似于Control.Invoke- 实际上是Controlimplements ISynchronizeInvoke)。它阻塞进程中的线程池线程。如果SynchronizingObjectnull它只是触发Elapsed线程池线程上的事件。此类的唯一真正用途是如果您需要按时触发 UI 组件的计时器。如果您不需要同步,请使用 aSystem.Threading.Timer代替。

如果您需要确保Tick在下一个事件开始之前完全处理前一个事件(所有处理程序都已返回),您需要:

  • 使计时器一次性而不是周期性,并让最后一个处理程序在完成执行时设置另一个镜头
  • 使用lockorMonitor来防止两个线程进入处理程序(但您可以用完线程池中的所有线程)
  • 用于Monitor.TryEnter仅在前一个已完成时进入处理程序(但您可能会错过一些Ticks)。
于 2013-05-24T17:00:14.087 回答