C#定时器是否在单独的线程上经过?

时间:2009-09-16 22:36:45

标签: c# multithreading timer

System.Timers.Timer是否在与创建它的线程不同的线程上经过?

假设我有一个班级,每5秒就有一个计时器。当计时器触发时,在已用方法中,某些对象被修改。让我们说修改这个对象需要很长时间,比如10秒。在这种情况下,我是否可能遇到线程冲突?

5 个答案:

答案 0 :(得分:179)

这取决于。 System.Timers.Timer有两种操作模式。

如果SynchronizingObject设置为ISynchronizeInvoke实例,则Elapsed事件将在托管同步对象的线程上执行。通常,这些ISynchronizeInvoke实例都是我们熟悉的普通旧ControlForm实例。因此,在这种情况下,在UI线程上调用Elapsed事件,它的行为类似于System.Windows.Forms.Timer。否则,它实际上取决于所使用的特定ISynchronizeInvoke实例。

如果SynchronizingObject为null,则在Elapsed线程上调用ThreadPool事件,其行为类似于System.Threading.Timer。事实上,它实际上在幕后使用System.Threading.Timer并在之后进行编组操作,如果需要,它会收到定时器回调。

答案 1 :(得分:54)

适用于System.Timers.Timer

请参阅Brian Gideon's answer below

适用于System.Threading.Timer

MSDN Documentation on Timers州:

  

System.Threading.Timer类制作   ThreadPool线程上的回调和   根本不使用事件模型。

确实,计时器在另一个线程上流逝。

答案 2 :(得分:20)

除非之前的Elapsed仍在运行,否则每个已用事件都将在同一个线程中触发。

所以它为你处理碰撞

尝试将其放入控制台

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秒钟来编辑你需要一些锁定来跳过一些编辑。

答案 3 :(得分:13)

对于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在Workers线程上执行。

不,进一步的并发症 - 如果你将间隔减少到10毫秒,

Main Thread Id: 9
   11
   13
   12
   22
   17
   ... 

这是因为如果在下一个tick被触发时没有完成OnDummyTimerFired的上一次执行,那么.NET将创建一个新线程来完成这项工作。

进一步复杂化,&#34; System.Timers.Timer类提供了一种处理这种困境的简单方法 - 它公开了一个公共的SynchronizingObject属性。将此属性设置为Windows窗体(或Windows窗体上的控件)的实例将确保Elapsed事件处理程序中的代码在实例化SynchronizingObject的同一线程上运行。&#34; < / p>

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

答案 4 :(得分:12)

如果经过的事件比间隔时间长,它将创建另一个线程来提升已经过去的事件。但是这个

有一个解决方法
static void timer_Elapsed(object sender, ElapsedEventArgs e)    
{     
   try
   {
      timer.Stop(); 
      Thread.Sleep(2000);        
      Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);    
   }
   finally
   {
     timer.Start();
   }
}