1

VB.NET 2010、.NET 4

大家好,

我有一个 System.Timers.Timer 对象,它对其经过的事件做了一些工作:

Private Sub MasterTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles MasterTimer.Elapsed
    MasterTimer.Enabled = False
    '...work...
    MasterTimer.Enabled = True
End Sub

我的问题是它所做的工作有时会卡住。部分工作是串行通信,因此它可能会在等待某物的响应时卡住。我已经稍微修改了我的串行通信代码,希望能解决这个问题。然而,这个计时器基本上是生产控制应用程序的心跳,如果它因任何原因停止是非常糟糕的。我在想设置一个故障安全超时可能会很好,这样,如果“工作”花费的时间太长,计时器可以重新启用自己并重试。我在想这样的事情:

将工作移入子例程并创建委托:

Private Delegate Sub WorkDelegate()
Private Sub Work()
   '...work...
End Sub

通过调用委托来调用工作,然后在 IAsyncResult 上使用 WaitOne(timeout) 来指定超时:

Private Sub MasterTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles MasterTimer.Elapsed
    MasterTimer.Enabled = False
    Dim workDel as New WorkDelegate(AddressOf Work)
    Dim result as IAsyncResult = workDel.BeginInvoke
    result.AsyncWaitHandle.WaitOne(CInt(MasterTimer.Interval))
    MasterTimer.Enabled = True
End Sub

但是,我的问题是:如果 Work() 真的被卡在某个地方,这会导致问题吗?因为它会重新进入一个已经运行的子程序?如果 Work() 在超时后没有完成,有没有办法中止它?换句话说,如果在 WaitOne 之后 result.IsCompleted 为 False,就停止 Work() 的执行?

我不太了解这些东西,所以,任何意见将不胜感激。也许有一种我不知道的完全不同的方法来解决这个问题?

提前非常感谢!

我想补充一点:

虽然我打算按照 Hans 的建议进行一些重写,但我已经安排了一天的测试来尝试隔离这个错误的来源。到目前为止,它仅在运行已编译的应用程序时发生。我今天(和昨天)花了一些时间尝试在调试模式下运行时重现冻结,以便我可以添加一些断点并弄清楚发生了什么。到目前为止,该程序还没有在调试模式下冻结。我只是想知道调试环境是否有任何不同可以解释这一点。可能只是我很“幸运”,但我运行它的时间可能是程序在运行可执行文件时冻结的平均时间的三倍......再次,我很无知,但是调试环境有什么独特之处可以解释这一点吗?如果它冻结,我会再次更新。

4

1 回答 1

2

这在代码的第一行就出错了。System.Timers.Timer 类非常讨厌,绝对不能保证调用 Stop() 会阻止另一个调用。计时器使用 ThreadPool.QueueUserWorkItem 进行 Elapsed 事件处理程序调用。如果线程池很忙,这可能最终会排队几个调用,等待从 TP 调度程序开始运行。停止计时器并不会阻止那些等待的线程运行。如果不使用锁,这些线程会严重地相互踩踏并打乱您的通信状态。

一个安全的是 System.Threading.Timer ,它的周期为零,所以你只会得到一个回调。使用其 Change() 方法为计时器充电。

调用委托的 BeginInvoke() 方法然后阻止它完成是没有意义的。只需调用 Invoke()。使您免于烧毁另一个线程。

是的,如果“工作”方法永远不会返回,那么您就有问题了。一个无解的。

如果您避免使用轮询来查看串行端口上是否有任何可用的东西,那么很多这种痛苦可能会消失。让它告诉你有一些值得去做的事情。只要接收缓冲区中至少有一个字节,它就会在线程池线程上引发 DataReceived 事件。使用它的 WriteTimeout 属性也是避免在通信协议或设备出现问题时卡住的好方法。专用一个线程并进行阻塞读取调用也很有效。

于 2010-10-06T20:21:22.350 回答