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实例是我们都熟悉的普通的ControlForm实例。 所以在这种情况下, 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实例化的同一个线程上运行。

http://msdn.microsoft.com/en-us/magazine/cc164015.aspx#S2