我使用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正在运行时,应该停止计时器。
有什么想法吗?
答案 0 :(得分:3)
.NET Framework中有两个主要的计时器类:线程计时器和窗口计时器。
System.Threading.Timer
是线程计时器的基本类。这包装了Windows waitable timer object。 Tick
会触发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
)。它会阻塞进程中的线程池线程。如果SynchronizingObject
为null
,则只会触发线程池线程上的Elapsed
事件。此类的唯一真正用途是,如果您需要按时触发UI组件的计时器。如果您不需要同步,请改用System.Threading.Timer
。
如果您需要确保在下一个Tick
事件已完全处理之前(所有处理程序都已返回),则需要启动下一个事件:
lock
或Monitor
阻止两个线程进入处理程序(但您可以用完线程池中的所有线程)Monitor.TryEnter
仅在前一个处理程序完成时输入处理程序(但您可能会错过一些Tick
)。