System.Windows.Forms.Timer是否在UI线程之外运行?

26

我有一个主线程创建一个表单对象,该表单对象设置了一个定时器每分钟运行一次名为updateStatus()的函数。但是,updateStatus()也被主线程在几个地方调用。

然而,我不清楚这是否会导致任何同步问题。在C#中,System.Windows.Forms.Timer是否在与主线程不同的线程上运行?

6个回答

26

不,计时器事件是在UI线程上触发的。

您不会有任何同步问题。这是WinForms应用程序中使用的正确版本的计时器控件;它是专门设计来执行您所要求的操作的。它在幕后使用标准的Windows计时器实现。

文档在备注部分确认了这一点:

定时器用于在用户定义的时间间隔内引发事件。此Windows计时器适用于单线程环境,其中使用UI线程执行处理。它要求用户代码有一个可用的UI消息泵,并始终从相同的线程操作,或将调用排队到另一个线程。

当您使用此计时器时,请使用Tick事件执行轮询操作或显示指定时间的启动屏幕。每当Enabled属性设置为true且Interval属性大于零时,Tick事件会根据Interval属性设置间隔地引发。


那么Windows计时器正在主线程上运行,它将始终是同步的,我不需要在updateStatus()函数中放置锁块。我是正确的吗? - user186246
@user:是的,没错。它的运行方式就像在你的窗体上引发的任何其他事件一样,比如PaintLoad事件。你也不需要锁定这些处理程序。 - Cody Gray

9
不,计时器的Tick事件是通过消息循环从UI线程触发的,当它接收到WM_TIMER消息时。只有在UI线程空闲时才可以运行。

5

不。

Windows.Forms计时器的整个重点在于它在GUI线程上运行。

Windows (WinForms) 运行的是一种称为“消息泵”的东西(请参见Application.Run()),这就使得计时器成为可能。

您所有的代码都作为事件处理程序的一部分运行,而计时器的滴答声永远不会“中断”任何其他事件处理程序。


嗨,我不了解messagePump。你能否提供一些相关信息? - user186246

4

Windows.Forms计时器将事件通过同步上下文返回到UI线程。

如果你想使用非UI线程,可以使用其他计时器,例如System.Timers.Timer或System.Threading.Timer。


2
不完全正确。它使用Windows消息,因此永远不会离开UI线程。 - SLaks

2
根据文档,计时器在主UI线程上运行:
计时器用于在用户定义的时间间隔内触发事件。此Windows计时器设计用于单线程环境,其中UI线程用于执行处理。它要求用户代码有一个可用的UI消息泵,并始终从同一线程操作,或将调用封送到另一个线程。

-1

我不想贬低其他回答者的声誉,他们说Windows.Forms.Timer总是在GUI线程上运行,但我必须反驳一下。 :)

我的回答是 - 这取决于情况。 Windows.Forms.Timer可能会在非GUI线程上运行!

Windows.Forms.Timer会在包含计时器的Form所在的线程上触发Timer.Tick事件。

如果该窗体是在GUI线程上创建的,则Timer.Tick在GUI线程上运行,但如果Form是在例如某个线程池中的XXX线程上创建的(应避免这种情况),则Timer.Tick将在此XXX线程上运行。

Task.Run(()=>
{
    using (var formWithTimer = new SomeFormWithTimer()) //Form created on worker thread, Tick handled on it.
    {
        formWithTimer.ShowDialog();
    }
});

@HenkHolterman,您的意思是我的答案是错误的吗? - Rekshino
@HenkHolterman,你是否同意 Timer.Tick 可能在非 GUI 线程上运行的情况下?;) - Rekshino
这不是我的问题,回答中也指出不应该这样做。回答在这里作为补充强调,Timer.Tick 不一定必须在 GUI 线程上运行,即使这不是一个现实的情况。 - Rekshino

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接