System.Timers.Timer是否在与创建它的线程不同的线程上经过?
假设我有一个班级,每5秒就有一个计时器。当计时器触发时,在已用方法中,某些对象被修改。让我们说修改这个对象需要很长时间,比如10秒。在这种情况下,我是否可能遇到线程冲突?
答案 0 :(得分:179)
这取决于。 System.Timers.Timer
有两种操作模式。
如果SynchronizingObject
设置为ISynchronizeInvoke
实例,则Elapsed
事件将在托管同步对象的线程上执行。通常,这些ISynchronizeInvoke
实例都是我们熟悉的普通旧Control
和Form
实例。因此,在这种情况下,在UI线程上调用Elapsed
事件,它的行为类似于System.Windows.Forms.Timer
。否则,它实际上取决于所使用的特定ISynchronizeInvoke
实例。
如果SynchronizingObject
为null,则在Elapsed
线程上调用ThreadPool
事件,其行为类似于System.Threading.Timer
。事实上,它实际上在幕后使用System.Threading.Timer
并在之后进行编组操作,如果需要,它会收到定时器回调。
答案 1 :(得分:54)
请参阅Brian Gideon's answer below
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>
答案 4 :(得分:12)
如果经过的事件比间隔时间长,它将创建另一个线程来提升已经过去的事件。但是这个
有一个解决方法static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
timer.Stop();
Thread.Sleep(2000);
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
}
finally
{
timer.Start();
}
}