计时器事件委托是否作为线程安全进程调用?
本文关键字:安全 线程 进程 调用 事件 是否 计时器 | 更新日期: 2023-09-27 17:49:42
我有2个定时器 (System.Timers.Timer)运行,两个计时器都有委托订阅。两个方法(在订阅的委托中)都处理相同的对象(例如列表和列表中的对象)。
假设计时器Elapsed-Events在同时被调用。
委托会在不同的线程中运行吗?或者他们将被一个接一个地称呼?我应该让代码线程安全,并使用锁吗?
我想你指的是System.Timers.Timer而不是System.Windows.Forms.Timer。如文档所述:
基于服务器的Timer被设计用于多线程环境中的工作线程。服务器计时器可以在线程之间移动以处理引发的Elapsed事件,从而比Windows计时器更准确地按时引发事件。
没有什么可以保证两个不同的线程不会为两个不同的计时器引发Elapsed
事件。最好让你的代码线程安全。
我添加了一个简短的代码片段来显示Elapsed
的多个回调可以同时被调用(在这种情况下,会导致死锁——Debug.WriteLine
永远不会被调用)。
var _lock = new object();
GC.KeepAlive(_lock);
var timer1 = new Timer(100);
var timer2 = new Timer(200);
timer1.Elapsed += delegate
{
lock (_lock)
Thread.Sleep(-1);
};
timer2.Elapsed += delegate
{
lock (_lock)
Debug.WriteLine("Hello world.");
};
timer1.Start();
timer2.Start();
定时器回调(您不指定特定的类/命名空间)总是在单独的线程中调用。所以你应该让你的代码线程安全。它们是否会被称为"同时"或随后偏离航线取决于它们的区间集。对于相同的间隔集,首先调用哪个回调几乎是不确定的。
它们将作为工作项在ThreadPool中排队,因此,是的,它们存在并发执行的风险。确保这种情况不会发生的一种方法是只调度单个计时器回调并将循环时间设置为无穷大(System.Threading.Timer
支持此方法),并在工作完成时重新调度。