【问题标题】:Do System.Timers.Timer run in independent Threads?System.Timers.Timer 是否在独立线程中运行?
【发布时间】:2011-10-26 02:19:47
【问题描述】:

我试图了解System.Timers.Timer 何时引发已逝事件,它是在独立线程中引发的吗?

我下面的例子似乎表明三个计时器在各自的线程中独立运行:

class Program
{
    static System.Timers.Timer timer = new System.Timers.Timer();
    static System.Timers.Timer timer2 = new System.Timers.Timer();
    static System.Timers.Timer timer3 = new System.Timers.Timer();

    static void Main(string[] args)
    {
        timer.Elapsed += new System.Timers.ElapsedEventHandler(
            timer_Elapsed);
        timer2.Elapsed += new System.Timers.ElapsedEventHandler(
            timer2_Elapsed);
        timer3.Elapsed += new System.Timers.ElapsedEventHandler(
            timer3_Elapsed);

        timer.Interval = 1000;
        timer2.Interval = 1000;
        timer3.Interval = 1000;

        timer.Start();
        timer2.Start();
        timer3.Start();

        Console.WriteLine("Press \'q\' to quit the sample.");
        while (Console.Read() != 'q') ;
    }

    static void timer3_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        timer3.Stop();
        Console.WriteLine("Timer 3 Hit...");            
        timer3.Start();
    }

    static void timer2_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        timer2.Stop();
        Console.WriteLine("Timer 2 Hit...");
        Thread.Sleep(2000);
        timer2.Start();
    }

    static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        timer.Stop();
        Console.WriteLine("Timer 1 Hit...");
        Thread.Sleep(10000);
        timer.Start();
    }
}

【问题讨论】:

  • 是的,它们在不同的线程中运行。
  • System.Timers.Timer 在内部使用System.Threading.Timer(在thread pool 线程上执行单个回调方法)。见source code

标签: c# .net timer


【解决方案1】:

根据 MSDN,在 System.Timers.Timer 上,当 Elapsed 事件触发时,它会在系统线程池中的线程上调用:

如果 SynchronizingObject 属性为 Nothing,则在 ThreadPool 线程上引发 Elapsed 事件。如果 Elapsed 事件的处理持续时间超过 Interval,则该事件可能会在另一个 ThreadPool 线程上再次引发。在这种情况下,事件处理程序应该是可重入的。

由于SynchronizingObject 的默认值为null,那么您所有的已用事件都将在线程池中处理。所以,这取决于线程池有多满,如果有空闲线程,那么每个经过的事件很可能在单独的线程上同时运行。但是,如果由于某种原因,系统线程池已经被完全使用,那么经过的事件可能会在安排时被序列化。

重点是:“视情况而定。”也就是说,只要池中有空闲线程,它们就可以并行运行。

参考:MSDN on System.Timers.Timer

【讨论】:

  • 所有答案都是正确的,但是我觉得 ThreadPool 是这里的关键组件。
【解决方案2】:

根据您的代码,它们必须是,因为Thread.Sleep 是一个阻塞调用。如果它们在同一个线程上运行,其他计时器都不会触发。

你可以在每一个中输出System.Threading.Thread.CurrentThread.ManagedThreadId来确定。

【讨论】:

    【解决方案3】:

    这很复杂。 documentation 表示以下内容:

    基于服务器的计时器设计用于多线程环境中的工作线程。服务器计时器可以在线程之间移动以处理引发的 Elapsed 事件,从而在按时引发事件方面比 Windows 计时器更准确。

    然后是这个:

    如果 SynchronizingObject 属性为 null,则在 ThreadPool 线程上引发 Elapsed 事件。如果 Elapsed 事件的处理持续时间超过 Interval,则该事件可能会在另一个 ThreadPool 线程上再次引发。在这种情况下,事件处理程序应该是可重入的。

    然后是这个:

    如果您将 Timer 与用户界面元素(例如表单或控件)一起使用,但未将计时器放置在该用户界面元素上,请将包含 Timer 的表单或控件分配给 SynchronizingObject 属性,以便事件发生编组到用户界面线程。

    因此,对于您的问题“它是在独立线程中提出的吗?”没有简单的答案。这取决于很多事情。

    【讨论】:

      【解决方案4】:

      是的,每次调用 Elapsed 时,都会在其自己的线程上触发回调。

      此外,没有什么可以阻止 Elapsed 事件处理程序在前一个事件处理程序完成之前触发。例如,如果您的计时器每 500 毫秒触发一次,但 Elapsed 事件处理程序代码需要 2 秒才能完成,则 Elapsed 代码可以访问相同的资源(非线程安全对象、文件等)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多