首页 > 解决方案 > 在 Windows 服务中从事件处理程序启动计时器

问题描述

我有一个内置于 vb.net 的 Windows 服务,它接收来自 MQTT 服务器的消息。消息通过附加到事件处理程序的 Sub 接收和处理。工作正常。

此外,我需要启动一个定时器,它将并行发送一个信号到“蜂鸣器”,蜂鸣器,停止,蜂鸣器......这个子例程本身就可以正常工作。

在 Windows 服务和 Windows 窗体中,它都不能完美运行。Timer 必须由链接到 Event Handler 的 Sub 启用(一旦收到并处理 MQTT 消息,启动计时器)。定时器通常设置为 1000ms。子例程在 Timer 到达 1000ms 之前完成,并且永远不会触发 Tick 事件。

在 Windows 窗体中,我使用 Me.Invoke 解决了这个问题。Timer's Tick 事件按预期触发。但是 Windows 服务中不存在“me.invoke”。我不知道如何继续触发 Tick 事件。

在 Windows 窗体中,我能够创建一个委托并使用 Me.Invoke 调用 RefreshMqttScreen ...

所以问题是:一旦 MqttMessageReceived 子程序完成运行,如何让计时器继续运行?

如果 VB 不能满足我的需求,我可以使用 C#...

谢谢

    AddHandler _mqttClient.ApplicationMessageReceived, AddressOf MqttMessageReceived



Public Sub MqttMessageReceived(ByVal sender As Object, ByVal e As MqttApplicationMessageReceivedEventArgs)
       RefreshMQTTScreen(some parameters here)
End Sub


Private Sub RefreshMQTTScreen(....)
    indexBuzzer = 1
    TimerBuzzer.Interval = buzzer.intDuree
    TimerBuzzer.Enabled = True
End Sub

Private Sub TimerBuzzer_Tick(sender As Object, e As EventArgs) Handles TimerBuzzer.Tick
    TimerBuzzer.Enabled = False
    indexBuzzer += 1

    If collBuzzerActif.Count >= indexBuzzer Then
        Dim buzzer As Derby.ClsBuzzer
        buzzer = collBuzzerActif(indexBuzzer)
        If buzzer.boolOn And buzzer.intDuree > 0 Then
            ChangerStatutDataLogger(True)
            If collBuzzerActif.Count >= indexBuzzer + 1 Then
                TimerBuzzer.Interval = buzzer.intDuree
                TimerBuzzer.Enabled = True
            End If
        Else
            ChangerStatutDataLogger(False)
            If collBuzzerActif.Count >= indexBuzzer + 1 Then
                TimerBuzzer.Interval = buzzer.intDuree
                TimerBuzzer.Enabled = True
            End If
        End If
    End If

End Sub

标签: c#vb.netmultithreadingtimerevent-handling

解决方案


您可以使用任务和一些 ManualResetEvent,而不是使用计时器。当您的服务开始执行此 ONCE 时,

_TimerBuzzerTask = Task.Run(Sub() TimerBuzzer_Tick())

然后进行这些更改

Private Sub RefreshMQTTScreen(....)
    indexBuzzer = 1
    TimerBuzzerInterval = buzzer.intDuree
    _TimerBuzzer_Enabled.Set()
End Sub

Private _TimerBuzzerTask As Task
Private _TimerBuzzer_Enabled As New Threading.ManualResetEvent(False)
Private _TimerBuzzer As New Threading.ManualResetEvent(False) '_TimerBuzzer.Set to end task
Private TimerBuzzerInterval As Integer = 1000

Private Sub TimerBuzzer_Tick()
    Do
        _TimerBuzzer_Enabled.WaitOne() 'to enable  _TimerBuzzer_Enabled.Set()
        _TimerBuzzer_Enabled.Reset()
        If collBuzzerActif.Count >= indexBuzzer Then
            Dim buzzer As Derby.ClsBuzzer
            buzzer = collBuzzerActif(indexBuzzer)

            If buzzer.boolOn AndAlso buzzer.intDuree > 0 Then
                ChangerStatutDataLogger(True)
                If collBuzzerActif.Count >= indexBuzzer + 1 Then
                    TimerBuzzerInterval = buzzer.intDuree
                    _TimerBuzzer_Enabled.Set()
                End If
            Else
                ChangerStatutDataLogger(False)
                If collBuzzerActif.Count >= indexBuzzer + 1 Then
                    TimerBuzzerInterval = buzzer.intDuree
                    _TimerBuzzer_Enabled.Set()
                End If
            End If

        End If
    Loop While _TimerBuzzer.WaitOne(TimerBuzzerInterval) 'ticks every second
End Sub

如果您的服务停止执行此操作,

 _TimerBuzzer.Set

由于显而易见的原因,我无法对此进行测试。


推荐阅读