System.Timers.Timer是否在与创建它的线程不同的线程上运行?
可以说我有一个带有计时器的类,该计时器每5秒触发一次。当计时器触发时,在经过的方法中,某些对象被修改。可以说,修改该对象需要很长时间,例如10秒。在这种情况下,是否可能会遇到线程冲突?
Answers:
这取决于。将System.Timers.Timer
有两种操作模式。
如果SynchronizingObject
将设置为ISynchronizeInvoke
实例,则Elapsed
事件将在托管同步对象的线程上执行。通常这些ISynchronizeInvoke
实例是没有比普通的老式其他Control
和Form
情况下,我们都熟悉。因此,在那种情况下,Elapsed
事件是在UI线程上调用的,其行为类似于System.Windows.Forms.Timer
。否则,它实际上取决于所使用的特定ISynchronizeInvoke
实例。
如果SynchronizingObject
为null,则在线程Elapsed
上调用该事件ThreadPool
,其行为类似于System.Threading.Timer
。实际上,它实际上在System.Threading.Timer
后台使用了一个幕后,并在收到计时器回调(如果需要)之后进行编组操作。
System.Threading.Timer
or还是System.Timers.Timer
?
System.Timers.Timer
都有两种操作模式。它可以在随机分配的线程池线程上运行,也可以在托管ISynchronizeInvoke
实例的任何线程上运行。我不知道该如何澄清。System.Threading.Timer
与原始问题关系不大(如果有的话)。
lock
吗?
除非先前的“经过”仍在运行,否则每个经过的事件都将在同一线程中触发。
因此它为您处理了碰撞
尝试将其放在控制台中
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
由于没有碰撞。
但这仍然给您带来问题。如果u每5秒触发一次事件,并且需要10秒钟进行编辑,则需要进行一些锁定才能跳过某些编辑。
timer.Stop()
在Elapsed事件方法的开头添加a ,然后在Elapsed事件方法timer.Start()
的末尾添加a 可以防止Elapsed事件发生冲突。
对于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
...
这是因为,如果在触发下一个刻度时未完成OnDummyTimerFired的先前执行,则.NET将创建一个新线程来执行此工作。
更复杂的是,“ System.Timers.Timer类提供了一种解决此难题的简便方法,它公开了一个公共的SynchronizingObject属性。将该属性设置为Windows Form实例(或Windows Form上的控件)将确保您的Elapsed事件处理程序中的代码将在实例化SynchronizingObject的同一线程上运行。”
如果经过的事件花费的时间比间隔时间长,它将创建另一个线程来引发经过的事件。但是有一个解决方法
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
timer.Stop();
Thread.Sleep(2000);
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
}
finally
{
timer.Start();
}
}