多线程挂起主线程,按顺序进行。

Multi-thread haning up main thread, going in order.

我遇到了挂起我的主线程的多线程 ping 问题。在调试问题时,我注意到当主线程挂起时,它正在启动每个线程并移动到下一个线程以进行 ping 操作。基本上它必须 ping 5 个不同的 IP 地址,如果它们都关闭,我的整个线程将挂起 20 - 30 秒。我正在使用 BeginInvoke,但它似乎仍然无法正常工作。

另一个奇怪的地方是我在每个线程的末尾添加了一个消息框,只是为了看看它们是如何完成的。我有 5 个线程,每个线程的末尾都弹出一个消息框,上面写着 "Done." 好吧,它不是只弹出 5 次,而是出现 10 次,就好像 运行 两次一样。通常我在这些线程中没有消息框,它只是让我尝试弄清楚发生了什么,但我很难过。

这将获取 IP 地址并启动线程:

Private Sub PingThreadStart()

    Host = zeroStoreNum


    IP = "10."
    Select Case (Host.Substring(0, 1))
        Case "0"
            IP = IP & "10."
        Case "1"
            IP = IP & "11."
        Case "2"
            IP = IP & "12."
        Case "3"
            IP = IP & "13."
        Case "4"
            IP = IP & "14."
        Case "5"
            IP = IP & "15."
        Case "6"
            IP = IP & "16."
        Case "7"
            IP = IP & "17."
        Case "8"
            IP = IP & "18."
        Case "9"
            IP = IP & "19."
    End Select

    Select Case (Host.Substring(1, 1))
        Case "0"
            'IP = IP & "0"
        Case "1"
            IP = IP & "1"
        Case "2"
            IP = IP & "2"
        Case "3"
            IP = IP & "3"
        Case "4"
            IP = IP & "4"
        Case "5"
            IP = IP & "5"
        Case "6"
            IP = IP & "6"
        Case "7"
            IP = IP & "7"
        Case "8"
            IP = IP & "8"
        Case "9"
            IP = IP & "9"
    End Select

    Select Case (Host.Substring(2, 1))
        Case "0"
            IP = IP & "0."
        Case "1"
            IP = IP & "1."
        Case "2"
            IP = IP & "2."
        Case "3"
            IP = IP & "3."
        Case "4"
            IP = IP & "4."
        Case "5"
            IP = IP & "5."
        Case "6"
            IP = IP & "6."
        Case "7"
            IP = IP & "7."
        Case "8"
            IP = IP & "8."
        Case "9"
            IP = IP & "9."
    End Select
    If Host = 100 Then
        IP = "10.10.100."
    End If
    If Host = 200 Then
        IP = "10.11.100."
    End If
    If Host = 300 Then
        IP = "10.12.100."
    End If
    If Host = 400 Then
        IP = "10.13.100."
    End If
    If Host = 500 Then
        IP = "10.14.100."
    End If
    If Host = 600 Then
        IP = "10.15.100."
    End If
    If Host = 700 Then
        IP = "10.16.100."
    End If
    If Host = 800 Then
        IP = "10.17.100."
    End If
    If Host = 900 Then
        IP = "10.18.100."
    End If

    lblIPschemeCH.Text = IP & "X"

    SonicWALL = IP & "1"
    primary = IP & "2"
    secondary = IP & "3"

    Dim PingPublicTry As Thread = New Thread(AddressOf PingPublicTH)
    Dim PingSWpublicTry As Thread = New Thread(AddressOf PingSWpublicTH)
    Dim PingDotOneTry As Thread = New Thread(AddressOf PingDotOneTH)
    Dim PingDotTwoTry As Thread = New Thread(AddressOf PingDotTwoTH)
    Dim PingDotThreeTry As Thread = New Thread(AddressOf PingDotThreeTH)

    PingPublicTry.IsBackground = True
    PingSWpublicTry.IsBackground = True
    PingDotOneTry.IsBackground = True
    PingDotTwoTry.IsBackground = True
    PingDotThreeTry.IsBackground = True


    If ModemPublic = "DHCP" Or SonicWALLPublic = "DHCP" Then
        PingDotOneTry.Start()
        PingDotTwoTry.Start()
        PingDotThreeTry.Start()
    Else
        PingPublicTry.Start()
        PingSWpublicTry.Start()
        PingDotOneTry.Start()
        PingDotTwoTry.Start()
        PingDotThreeTry.Start()
    End If



End Sub

这是我的足迹:

    Private Sub PingPublicTH()
    Dim pingactmodem As New System.Net.NetworkInformation.Ping
    Dim pingretmodem As System.Net.NetworkInformation.PingReply
    Dim speedmodem As Integer

    Try
        pingretmodem = pingactmodem.Send(ModemPublic)
        speedmodem = pingretmodem.RoundtripTime
    Catch ex As Exception

    End Try

    If (lblModCh.InvokeRequired) Then

        Dim show As New PingPublicDel(AddressOf PingPublicTH)
        Me.lblModCh.BeginInvoke(show)
    Else
        If speedmodem >= 1 And speedmodem <= 500 Then
            lblModCh.BackColor = Color.Green
        ElseIf speedmodem >= 501 And speedmodem <= 1500 Then
            lblModCh.BackColor = Color.Orange
        ElseIf speedmodem >= 1501 Then
            lblModCh.BackColor = Color.Red
        ElseIf speedmodem = 0 Then
            lblModCh.BackColor = Color.Black

        End If
    End If
    MessageBox.Show("Done modem")


End Sub
Private Sub PingSWpublicTH()
    Dim pingactswp As New System.Net.NetworkInformation.Ping

    Dim pingretswp As System.Net.NetworkInformation.PingReply
    Dim speedswp As Integer

    Try
        pingretswp = pingactswp.Send(SonicWALLPublic)
        speedswp = pingretswp.RoundtripTime
    Catch ex As Exception
    End Try

    If (lbSWPCh.InvokeRequired) Then

        Dim show As New PingSwPublicDel(AddressOf PingSWpublicTH)
        Me.lbSWPCh.BeginInvoke(show)
    Else
        If speedswp >= 1 And speedswp <= 500 Then
            lbSWPCh.BackColor = Color.Green
        ElseIf speedswp >= 501 And speedswp <= 1500 Then
            lbSWPCh.BackColor = Color.Orange
        ElseIf speedswp >= 1501 Then
            lbSWPCh.BackColor = Color.Red
        ElseIf speedswp = 0 Then
            lbSWPCh.BackColor = Color.Black

        End If

    End If
    MessageBox.Show("Done swp")

End Sub
Private Sub PingDotOneTH()
    Dim pingact1 As New System.Net.NetworkInformation.Ping
    Dim pingret1 As System.Net.NetworkInformation.PingReply
    Dim speed1 As Integer



    pingret1 = pingact1.Send(SonicWALL)
    speed1 = pingret1.RoundtripTime

    If (lblSWch.InvokeRequired) Then

        Dim show As New PingDotOneDel(AddressOf PingDotOneTH)
        Me.lblSWch.BeginInvoke(show)

    Else

        If speed1 >= 1 And speed1 <= 500 Then
            lblSWch.Text = (speed1)
            lblSWch.BackColor = Color.Green
        ElseIf speed1 >= 501 And speed1 <= 1500 Then
            lblSWch.Text = (speed1)
            lblSWch.BackColor = Color.Orange
        ElseIf speed1 >= 1501 Then
            lblSWch.Text = (speed1)
            lblSWch.BackColor = Color.Red
        ElseIf speed1 = 0 Then
            lblSWch.Text = "Down"
            lblSWch.BackColor = Color.Black

        End If
    End If
    MessageBox.Show("Done .1")
End Sub
Private Sub PingDotTwoTH()
    Dim pingact2 As New System.Net.NetworkInformation.Ping
    Dim pingret2 As System.Net.NetworkInformation.PingReply
    Dim Speed2 As Integer


    pingret2 = pingact2.Send(primary)
    Speed2 = pingret2.RoundtripTime

    If (lblMainpcCH.InvokeRequired) Then
        Dim show As New PingDotTwoDel(AddressOf PingDotTwoTH)
        Me.lblMainpcCH.BeginInvoke(show)

    Else

        If Speed2 >= 1 And Speed2 <= 500 Then
            lblMainpcCH.Text = (Speed2)
            lblMainpcCH.BackColor = Color.Green
        ElseIf Speed2 >= 501 And Speed2 <= 1500 Then
            lblMainpcCH.Text = (Speed2)
            lblMainpcCH.BackColor = Color.Orange
        ElseIf Speed2 >= 1501 Then
            lblMainpcCH.Text = (Speed2)
            lblMainpcCH.BackColor = Color.Red
        ElseIf Speed2 = 0 Then
            lblMainpcCH.Text = "Down"
            lblMainpcCH.BackColor = Color.Black

        End If

    End If
    MessageBox.Show("Done .2")
End Sub
Private Sub PingDotThreeTH()
    Dim pingact3 As New System.Net.NetworkInformation.Ping
    Dim pingret3 As System.Net.NetworkInformation.PingReply
    Dim speed3 As Integer



    pingret3 = pingact3.Send(secondary)
    speed3 = pingret3.RoundtripTime


    If (lblSecondch.InvokeRequired) Then

        Dim show As New PingDotThreeDel(AddressOf PingDotThreeTH)

        Me.lblSecondch.BeginInvoke(show)

    Else

        If speed3 >= 1 And speed3 <= 500 Then
            lblSecondch.Text = (speed3)
            lblSecondch.BackColor = Color.Green
        ElseIf speed3 >= 501 And speed3 <= 1500 Then
            lblSecondch.Text = (speed3)
            lblSecondch.BackColor = Color.Orange
        ElseIf speed3 >= 1501 Then
            lblSecondch.Text = (speed3)
            lblSecondch.BackColor = Color.Red
        ElseIf speed3 = 0 Then
            lblSecondch.Text = "Down"
            lblSecondch.BackColor = Color.Black

        End If

    End If
    MessageBox.Show("Done .3")
End Sub

这里的问题是您再次调用相同的方法,这些方法在线程中应该是 运行。这会导致再次发送 ping 请求,但这次 UI 线程上的代码 运行s(因此它冻结的原因)。您应该确保只调用更新 UI.

的代码

这是可选的,但我建议您使用 extension method 来为您进行调用检查,因为它会提高可读性,但也会减少您必须编写的代码量:

Imports System.Runtime.CompilerServices

Public Module Extensions
    <Extension()> _
    Public Sub InvokeIfRequired(ByVal Control As Control, ByVal Method As [Delegate], ByVal ParamArray Parameters As Object())
        If Parameters Is Nothing OrElse _
            Parameters.Length = 0 Then Parameters = Nothing 'If Parameters is null or has a length of zero then no parameters should be passed.
        If Control.InvokeRequired = True Then
            Control.Invoke(Method, Parameters)
        Else
            Method.DynamicInvoke(Parameters)
        End If
    End Sub
End Module

现在,如果您的目标是 .NET Framework 4.0(或更高版本),您可以使用 lambda expression 进行快速的内联委托:

Me.InvokeIfRequired( _
    Sub()
        If speedmodem >= 1 AndAlso speedmodem <= 500 Then
            lblModCh.BackColor = Color.Green
        ElseIf speedmodem >= 501 And speedmodem <= 1500 Then
            lblModCh.BackColor = Color.Orange
        ElseIf speedmodem >= 1501 Then
            lblModCh.BackColor = Color.Red
        ElseIf speedmodem = 0 Then
            lblModCh.BackColor = Color.Black
        End If
    End Sub)

但是,如果您的目标是 .NET Framework 3.5 或更低版本,您必须以正常方式创建委托:

Private Delegate Sub UpdatePingStatusDelegate(ByVal speedmodem As Integer)

Private Sub PingPublicTH()
    ...your code...

    Me.InvokeIfRequired(New UpdatePingStatusDelegate(AddressOf UpdateStatusPublicTH), speedmodem)
End Sub

Private Sub UpdateStatusPublicTH(ByVal speedmodem As Integer)
    If speedmodem >= 1 AndAlso speedmodem <= 500 Then
        lblModCh.BackColor = Color.Green
    ElseIf speedmodem >= 501 And speedmodem <= 1500 Then
        lblModCh.BackColor = Color.Orange
    ElseIf speedmodem >= 1501 Then
        lblModCh.BackColor = Color.Red
    ElseIf speedmodem = 0 Then
        lblModCh.BackColor = Color.Black
    End If
End Sub

注:

  • 使用扩展方法 InvokeIfRequired 时,您无需检查其余代码中的 Control.InvokeRequired。您只需调用一次扩展方法,它就会为您进行检查。

  • 如果你使用我的第二种方法,你只需要一个 UpdatePingStatusDelegate 委托,如果你只需要一个整数来更新所有线程的状态。

请参阅 the difference between And and AndAlso