Vb.net 如何使BackgroundWorker的结果保持一致

Vb.net 如何使BackgroundWorker的结果保持一致,vb.net,multithreading,multiprocessing,backgroundworker,plc,Vb.net,Multithreading,Multiprocessing,Backgroundworker,Plc,我正在使用后台工作程序通过串行com端口通过MODBUS从我的PLC轮询数字IO状态。后台工作程序用于只读操作,每个周期之间的轮询速度为200毫秒。一个周期内要读取的I/O数约为50位(1个io状态=1个布尔值)。然后,我通过从UI线程将所有I/O切换到相反的状态(ON->OFF/OFF->ON),模拟对PLC的写入命令。我将Toggle()子例程放入一个间隔为100毫秒的计时器中,并执行3000毫秒。结果是一些端口不一致。启动状态为“全部打开”或“全部关闭”。切换后的预期结果也是全部打开或全部

我正在使用后台工作程序通过串行com端口通过MODBUS从我的PLC轮询数字IO状态。后台工作程序用于只读操作,每个周期之间的轮询速度为200毫秒。一个周期内要读取的I/O数约为50位(1个io状态=1个布尔值)。然后,我通过从UI线程将所有I/O切换到相反的状态(ON->OFF/OFF->ON),模拟对PLC的写入命令。我将Toggle()子例程放入一个间隔为100毫秒的计时器中,并执行3000毫秒。结果是一些端口不一致。启动状态为“全部打开”或“全部关闭”。切换后的预期结果也是全部打开或全部关闭。有时,最终结果是45 io打开,5 io关闭。有时它是40 io关闭和10 io打开。结果总是随机的,但决不是正确的结果,即所有io打开或所有io关闭

有趣的是,如果我使用定时器而不是后台工作程序进行轮询,则切换结果总是一致的(所有50个IO都是打开或关闭的)。我更喜欢使用后台工作程序进行轮询,因为UI要平滑得多。当我使用计时器时,UI感觉有点“滞后”。但是,后台工作人员正在导致不一致的结果

下面是我的代码的简化版本,以说明我的情况。我希望有人能给我指出正确的方向。后台工作人员正在轮询io状态。但是,只要我从UI线程操作端口,命令就不能100%保证始终执行,这对我来说是一个严重的问题

我将MODBUS读取操作放入DoWork子例程,并使用Backgroundworker.ReportProgress(0,objResult)将读取结果传递给UI线程。因此,对象的读写操作都发生在同一个UI线程中。为什么结果仍然不一致

Public Class Bit

Private _LastValue As Boolean
Private _Label As Control
Private DictControl As New Dictionary(Of String, Control)

Sub SetCoil(val As Boolean)
    'Do work here

    'Update last value
    SetLastValue(val)
End Sub

Function GetCoil() As Boolean
    Dim result As Boolean = True
    'Do work here

    'Update last value
    SetLastValue(result)

    Return result
End Function

Sub Toggle()
    Dim result As Boolean = Not _LastValue
    'invert current value
    'set current value = not current value

    'Update last value
    SetLastValue(result)
End Sub

Sub SetLastValue(val As Boolean)
    _LastValue = val

    Dim ctlText As String = ""

    If _LastValue = True Then
        ctlText = "ON"
    Else
        ctlText = "OFF"
    End If

    'Update label
    For Each c As KeyValuePair(Of String, Control) In DictControl
        c.Value.Text = ctlText
    Next

End Sub

Sub AddControl(key As String, c As Control)
    DictControl.Add(key, c)
End Sub

End Class

Public Class Main

Const BIT_COUNT = 50
Dim bgw As New System.ComponentModel.BackgroundWorker
Dim dictBit As New Dictionary(Of Integer, Bit)

Sub New()
    'Create a bunch of label and bit instances
    'Add label control to Bit
    'Add Bit to dictBit dictionary
    'Add Handler to Background Worker
    'Run Background Worker
    'Run Timer
End Sub

Sub bgw_DoWorkHandler(sender As Object, e As System.ComponentModel.DoWorkEventArgs)
    Dim Coils(49) As Boolean
    Dim result() As Boolean
    Dim run As Boolean = True

    Do
        'Do some processing & assign Coils value

        result = Coils.Clone 'Duplicate the variable
        bgw.ReportProgress(0, result)
        Sleep(300)
    Loop While run = True

End Sub

Sub bgw_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs)
    Dim results() As Boolean = DirectCast(e.UserState, Boolean())

    Dim i As Integer

    For i = 0 To UBound(results)
        If dictBit.ContainsKey(i) Then
            dictBit(i).SetLastValue(results(i)) 'Set last value and update Label
        End If
    Next
End Sub

Sub TimerTickHandler(ByVal sender As Object, ByVal e As EventArgs)
    'Background worker alternative.
    Dim Coils(49) As Boolean
    Dim result() As Boolean
    Dim run As Boolean = True

    'Do some work & assign Coils value
    result = Coils.Clone
    bgw.ReportProgress(0, result)

End Sub

Sub ToggleBits()
    Dim i As Integer

    For i = 0 To BIT_COUNT - 1
        dictBit(i).Toggle()
    Next
End Sub

Sub TimerToggleHandler(ByVal sender As Object, ByVal e As EventArgs)
    'Interval = 100 ms. Run for 3000 ms before stop.
    ToggleBits()
End Sub

End Class

切换期间,后台工作程序正在读取IO。这就是为什么所有的50点都不是相同的值

实际硬件输入可以随时更改。甚至在阅读前或阅读后的一瞬间也会出现这种情况。如果此切换例程仅用于测试,则忽略差异。否则,在切换结束时更新标志或触发事件。强制BW在读取之前等待切换完成的任何操作