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
Do C# Timers elapse on a separate thread?
提问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:
See Brian Gideon's answer below
请参阅下面的布赖恩·吉迪恩 (Brian Gideon) 的回答
MSDN Documentation on Timersstates:
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.Timer
has two modes of operation.
这取决于。将System.Timers.Timer
有两种操作模式。
If SynchronizingObject
is set to an ISynchronizeInvoke
instance then the Elapsed
event will execute on the thread hosting the synchronizing object. Usually these ISynchronizeInvoke
instances are none other than plain old Control
and Form
instances that we are all familiar with. So in that case the Elapsed
event is invoked on the UI thread and it behaves similar to the System.Windows.Forms.Timer
. Otherwise, it really depends on the specific ISynchronizeInvoke
instance that was used.
如果SynchronizingObject
设置为ISynchronizeInvoke
实例,则该Elapsed
事件将在托管同步对象的线程上执行。通常这些ISynchronizeInvoke
实例是没有比普通的老式其他Control
和Form
情况下,我们都熟悉。所以在这种情况下,Elapsed
事件在 UI 线程上被调用,它的行为类似于System.Windows.Forms.Timer
. 否则,它实际上取决于所使用的特定ISynchronizeInvoke
实例。
If SynchronizingObject
is null then the Elapsed
event is invoked on a ThreadPool
thread and it behaves similar to the System.Threading.Timer
. In fact, it actually uses a System.Threading.Timer
behind 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 实例化的同一线程上运行。”