定时器可以在backgroundworker中停止,但不能启动 [英] Timer can be stopped in backgroundworker, but can't be started

查看:79
本文介绍了定时器可以在backgroundworker中停止,但不能启动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,我一直在 UI 线程 中使用 system.form.timer.我已经注意到,虽然我可以在后台线程上停止计时器,但我无法启动它,除非我使用 BeginInvoke,即使我没有收到 cross-threading 异常代码>.但是,在 system.timers.timer 上,我似乎可以从计时器创建的后台线程中停止和启动它.为什么是这样?system.form.timer 是否允许停止,但不允许从后台线程启用?这对我来说似乎有点奇怪.

Recently, I've been working with a system.form.timer in the UI thread. I've have noticed that while I can stop a timer on a background thread, I cannot start it back up unless I use BeginInvoke even though I do not receive a cross-threading exception. On a system.timers.timer however it seems that I can stop and start it from the background thread created by the timer. Why is this? Is a system.form.timer allowed to be stopped, but not enabled from a background thread? This seems a bit odd to me.

不起作用

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    Dim BW As BackgroundWorker = New BackgroundWorker
    AddHandler BW.DoWork, AddressOf CheckTimer
    BW.RunWorkerAsync()
End Sub

Private Sub CheckTimer()
    Timer1.Stop()
    Timer1.Start()
    MsgBox("Stopped and Started Timer")
End Sub

工作

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    Dim BW As BackgroundWorker = New BackgroundWorker
    AddHandler BW.DoWork, AddressOf CheckTimer
    BW.RunWorkerAsync()
End Sub

Private Sub CheckTimer()
    Timer1.Stop()
    Me.BeginInvoke(New TimerStart(AddressOf TimerStartFunction))
    MsgBox("Stopped and Started Timer")
End Sub

Private Delegate Sub TimerStart()

Private Sub TimerStartFunction()
    Timer1.Start()
End Sub

System.Timers.Timer 代码

工作

Dim aTimer As System.Timers.Timer

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    aTimer = New System.Timers.Timer(5000)
    AddHandler aTimer.Elapsed, AddressOf OnTimedEvent
    aTimer.Enabled = True
End Sub

Sub OnTimedEvent()
    aTimer.Stop()
    aTimer.Start()
    MsgBox("Stopped and Started Timer")
End Sub

推荐答案

Winforms Timer 类某种程度上是线程安全的,不足以让您满意.当您调用它的 Start() 方法时,它会创建一个隐藏窗口,将 WM_TIMER 消息转换为 Tick 事件.

The Winforms Timer class is somewhat thread-safe, not enough to keep you happy. When you call its Start() method then it creates a hidden window that turns WM_TIMER messages into Tick events.

当您在工作线程上执行此操作时,您往往会遇到问题,这些 WM_TIMER 消息仅在线程运行消息循环时才会调度.工作线程通常不会这样做,它们不会调用 Application.Run().所以计时器不会打勾.

When you do this on a worker thread then you tend to have a problem, these WM_TIMER messages are only dispatched when the thread runs a message loop. Worker threads don't normally do this, they don't call Application.Run(). So the timer just won't tick.

否则调用 Stop() 方法是可以的,即使代码运行在错误的线程上,它也知道如何找到隐藏的窗口.您使用 BeginInvoke() 找到的解决方法有效,因为它现在可以在 UI 线程上正确调用 Start() 并获取使用正确的所有者线程创建的隐藏窗口,即泵.System.Timers.Timer 没有这个问题,它不依赖 WM_TIMER 来打勾,而是使用 System.Threading.Timer 代替.这是由 CLR 管理的专用工作线程支持的.请注意,此计时器非常危险.首先,在工作线程上调用 MsgBox() 从根本上是错误的.用户永远不会看到它的可能性很高,因为它位于 UI 窗口后面.

Calling the Stop() method is otherwise okay, it knows how to find that hidden window back even through the code runs on the wrong thread. The workaround you found with BeginInvoke() works because it now correctly calls Start() on the UI thread and gets the hidden window created with the correct owner thread, one that pumps. System.Timers.Timer doesn't have this problem, it doesn't rely on WM_TIMER to tick but uses a System.Threading.Timer instead. Which is supported by a dedicated worker thread managed by the CLR. Do note that this timer is pretty dangerous. Calling MsgBox() on a worker thread is fundamentally wrong, for one. High odds that the user never sees it since it will be behind a UI window.

这就解释了,我无法提供更好的建议,因为我看不到您真正想要做什么.小心,你在玩火.

That explains it, I can't otherwise offer better advice since I can't see what you are really trying to do. Be careful, you are playing with fire.

这篇关于定时器可以在backgroundworker中停止,但不能启动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆