C#定时器是否在单独的线程上运行?
System.Timers.Timer是否在一个单独的线程上执行,而不是创build它的线程?
比方说,我有一个每5秒钟触发一次的定时器。 当定时器触发时,在经过的方法中,某个对象被修改。 可以说,修改这个对象需要很长时间,比如10秒。 是否有可能在这种情况下遇到线程冲突?
对于System.Timers.Timer :
请参阅下面的Brian Gideon的答案
对于System.Threading.Timer :
有关定时器的MSDN文档指出:
System.Threading.Timer类在ThreadPool线程上进行callback ,根本不使用事件模型。
所以计时器的确在不同的线程上运行。
这取决于。 System.Timers.Timer
有两种操作模式。
如果SynchronizingObject
设置为ISynchronizeInvoke
实例,则Elapsed
事件将在承载同步对象的线程上执行。 通常这些ISynchronizeInvoke
实例是我们都熟悉的普通的Control
和Form
实例。 所以在这种情况下, Elapsed
事件在UI线程上被调用,它的行为类似于System.Windows.Forms.Timer
。 否则,它确实取决于所使用的特定ISynchronizeInvoke
实例。
如果SynchronizingObject
为null,则在ThreadPool
线程上调用Elapsed
事件,其行为与System.Threading.Timer
类似。 实际上,它实际上在后台使用System.Threading.Timer
,并在收到定时器callback后进行封送处理(如果需要的话)。
每个经过的事件都将在同一个线程中触发,除非之前的经历仍在运行。
所以它处理你的碰撞
尝试把这个在控制台
static void Main(string[] args) { Debug.WriteLine(Thread.CurrentThread.ManagedThreadId); var timer = new Timer(1000); timer.Elapsed += timer_Elapsed; timer.Start(); Console.ReadLine(); } static void timer_Elapsed(object sender, ElapsedEventArgs e) { Thread.Sleep(2000); Debug.WriteLine(Thread.CurrentThread.ManagedThreadId); }
你会得到这样的东西
10 6 12 6 12
其中10是调用线程,6和12是从bg过去的事件触发的。 如果你删除Thread.Sleep(2000); 你会得到这样的东西
10 6 6 6 6
由于没有碰撞。
但是这仍然使你面临一个问题。 如果你每5秒发射一次事件,编辑需要10秒钟,你需要一些locking来跳过一些编辑。
如果经过的事件需要更长的时间间隔,它将创build另一个线程来提高已经过的事件。 但是有一个解决方法
static void timer_Elapsed(object sender, ElapsedEventArgs e) { try { timer.Stop(); Thread.Sleep(2000); Debug.WriteLine(Thread.CurrentThread.ManagedThreadId); } finally { timer.Start(); } }
对于System.Timers.Timer,在单独的线程上,如果没有设置SynchronizingObject。
static System.Timers.Timer DummyTimer = null; static void Main(string[] args) { try { Console.WriteLine("Main Thread Id: " + System.Threading.Thread.CurrentThread.ManagedThreadId); DummyTimer = new System.Timers.Timer(1000 * 5); // 5 sec interval DummyTimer.Enabled = true; DummyTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnDummyTimerFired); DummyTimer.AutoReset = true; DummyTimer.Start(); Console.WriteLine("Hit any key to exit"); Console.ReadLine(); } catch (Exception Ex) { Console.WriteLine(Ex.Message); } return; } static void OnDummyTimerFired(object Sender, System.Timers.ElapsedEventArgs e) { Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId); return; }
如果DummyTimer以5秒的时间间隔触发,您将看到输出:
Main Thread Id: 9 12 12 12 12 12 ...
所以,如所见,OnDummyTimerFired在Worker线程上执行。
不,进一步的复杂性 – 如果你减less10毫秒的时间间隔,
Main Thread Id: 9 11 13 12 22 17 ...
这是因为如果OnDummyTimerFired的prev执行没有完成时,下一个滴答声被激发,然后.NET会创build一个新的线程来完成这项工作。
更复杂的事情, “System.Timers.Timer类提供了一个简单的方法来处理这个困境 – 它公开SynchronizingObject属性。将此属性设置为Windows窗体(或Windows窗体上的控件)的实例将确保您的Elapsed事件处理程序中的代码在SynchronizingObject实例化的同一个线程上运行。