C# 计时器是否在单独的线程上消逝?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1435876/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 16:30:34  来源:igfitidea点击:

Do C# Timers elapse on a separate thread?

c#multithreadingtimer

提问by user113164

Does a System.Timers.Timer elapse on a separate thread than the thread that created it?

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

Lets say I have a class with a timer that fires every 5 seconds. When the timer fires, in the elapsed method, some object is modified. Lets say it takes a long time to modify this object, like 10 seconds. Is it possible that I will run into thread collisions in this scenario?

假设我有一个带有每 5 秒触发一次的计时器的课程。当定时器触发时,在 elapsed 方法中,一些对象被修改。假设修改这个对象需要很长时间,比如 10 秒。在这种情况下我是否可能会遇到线程冲突?

采纳答案by Joren

For System.Timers.Timer:

对于System.Timers.Timer

See Brian Gideon's answer below

请参阅下面的布赖恩·吉迪恩 (Brian Gideon) 的回答

For System.Threading.Timer:

对于System.Threading.Timer

MSDN Documentation on Timersstates:

关于计时器的 MSDN 文档指出:

The System.Threading.Timer class makes callbacks on a ThreadPool threadand does not use the event model at all.

System.Threading.Timer 类在 ThreadPool 线程上进行回调并且根本不使用事件模型。

So indeed the timer elapses on a different thread.

所以确实计时器在不同的线程上过去了。

回答by Simon

Each elapsed event will fire in the same thread unless a previous Elapsed is still running.

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

So it handles the collision for you

所以它会为你处理碰撞

try putting this in a console

尝试将其放在控制台中

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);
}

you will get something like this

你会得到这样的东西

10
6
12
6
12

where 10 is the calling thread and 6 and 12 are firing from the bg elapsed event. If you remove the Thread.Sleep(2000); you will get something like this

其中 10 是调用线程,6 和 12 是从 bg elapsed 事件触发的。如果删除 Thread.Sleep(2000); 你会得到这样的东西

10
6
6
6
6

Since there are no collisions.

因为没有碰撞。

But this still leaves u with a problem. if u are firing the event every 5 seconds and it takes 10 seconds to edit u need some locking to skip some edits.

但这仍然给你留下了一个问题。如果您每 5 秒触发一次事件并且需要 10 秒进行编辑,则您需要锁定以跳过某些编辑。

回答by Brian Gideon

It depends. The System.Timers.Timerhas two modes of operation.

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

If SynchronizingObjectis set to an ISynchronizeInvokeinstance then the Elapsedevent will execute on the thread hosting the synchronizing object. Usually these ISynchronizeInvokeinstances are none other than plain old Controland Forminstances that we are all familiar with. So in that case the Elapsedevent is invoked on the UI thread and it behaves similar to the System.Windows.Forms.Timer. Otherwise, it really depends on the specific ISynchronizeInvokeinstance that was used.

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

If SynchronizingObjectis null then the Elapsedevent is invoked on a ThreadPoolthread and it behaves similar to the System.Threading.Timer. In fact, it actually uses a System.Threading.Timerbehind the scenes and does the marshaling operation afterit receives the timer callback if needed.

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

回答by Rajan

If the elapsed event takes longer then the interval, it will create another thread to raise the elapsed event. But there is a workaround for this

如果经过的事件花费的时间比间隔时间长,它将创建另一个线程来引发经过的事件。但是有一个解决方法

static void timer_Elapsed(object sender, ElapsedEventArgs e)    
{     
   try
   {
      timer.Stop(); 
      Thread.Sleep(2000);        
      Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);    
   }
   finally
   {
     timer.Start();
   }
}

回答by Swab.Jat

For System.Timers.Timer, on separate thread, if SynchronizingObject is not set.

对于 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;
    }

Output you'd see if DummyTimer fired on 5 seconds interval:

如果 DummyTimer 以 5 秒间隔触发,您将看到的输出:

Main Thread Id: 9
   12
   12
   12
   12
   12
   ... 

So, as seen, OnDummyTimerFired is executed on Workers thread.

因此,如所见, OnDummyTimerFired 在 Workers 线程上执行。

No, further complication - If you reduce interval to say 10 ms,

不,更复杂的 - 如果你减少间隔说 10 毫秒,

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

This is because if prev execution of OnDummyTimerFired isn't done when next tick is fired, then .NET would create a new thread to do this job.

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

Complicating things further, "The System.Timers.Timer class provides an easy way to deal with this dilemma—it exposes a public SynchronizingObject property. Setting this property to an instance of a Windows Form (or a control on a Windows Form) will ensure that the code in your Elapsed event handler runs on the same thread on which the SynchronizingObject was instantiated."

更复杂的是,“System.Timers.Timer 类提供了一种简单的方法来处理这个困境——它公开了一个公共 SynchronizingObject 属性。将此属性设置为 Windows 窗体的实例(或 Windows 窗体上的控件)将确保Elapsed 事件处理程序中的代码在 SynchronizingObject 实例化的同一线程上运行。”

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

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