System.Timers.Timer方法中的线程

时间:2013-05-24 14:33:27

标签: c# multithreading timer

我使用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正在运行时,应该停止计时器。

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

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

System.Threading.Timer是线程计时器的基本类。这包装了Windows waitable timer objectTick会触发ThreadPool事件。 检查之前Tick的所有处理程序是否都已返回,然后再次触发Tick。计时器应按时启动 - 不会延迟。

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

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

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

  • 使计时器一次性而不是周期性,让最后一个处理程序在完成执行时设置另一个镜头
  • 使用lockMonitor阻止两个线程进入处理程序(但您可以用完线程池中的所有线程)
  • 使用Monitor.TryEnter仅在前一个处理程序完成时输入处理程序(但您可能会错过一些Tick)。