多线程处理主线程,按顺序进行. [英] Multi-thread haning up main thread, going in order.

查看:98
本文介绍了多线程处理主线程,按顺序进行.的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

另一个奇怪的是,我在每个线程的末尾添加了一个消息框,以查看它们的完成情况.我有5个线程,每个线程的末尾都有一个消息框,弹出并显示完成".好吧,它不是弹出仅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线程上运行(因此冻结).您应该确保仅调用更新UI的代码.

这是可选的,但我建议您使用 扩展名方法 为您执行调用检查,因为它可以提高可读性,但同时也减少了您必须编写的代码量:

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 (或更高版本)为目标,则可以使用 AndAndAlso 之间的区别. >

I'm having an issue with multithreading pings that are hanging up my main thread. When debugging the issue, I notice that while the main thread is hung up, it is starting each thread and moving to the next for the pings. Basically it has to ping 5 different IP addresses, and if they're all down my whole thread hangs up for 20 - 30 seconds. I'm using the BeginInvoke, but it still doesn't seem to work right.

Another oddity is that I added a message box at the end of each thread, just to see how they're completing. I have 5 threads and at the end of each is a message box that pops up and says "Done." Well, instead of popping up just 5 times, it's coming up 10 times as if it's running twice. Normally I don't have message boxes in these threads, it is just there for me to try and figure out what is going on, but I'm stumped.

This gets the IP addresses and starts the threads:

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

And this is my treads:

    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

解决方案

The problem here is that you invoke the same methods once again, which are supposed to be run in threads. This causes the ping request to be sent yet another time, but this time the code runs on the UI thread (hence why it freezes). You should make sure to only invoke the code that updates the UI.

This is optional, but I recommend you to use an extension method to do the invocation check for you since it will improve readability but also decrease the amount of code you have to write:

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

Now, if you target .NET Framework 4.0 (or higher) you can use a lambda expression for a quick, inline delegate:

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)

However if you target .NET Framework 3.5 or lower you have to create delegates the normal way:

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

Note:

  • When using the extension method InvokeIfRequired you don't need to check Control.InvokeRequired in the rest of your code. You only require the one call to the extension method and it will do the checking for you.

  • If you use my second method you only need the one UpdatePingStatusDelegate delegate if all you need is one integer to update the status from all the threads.

Please also see the difference between And and AndAlso.

这篇关于多线程处理主线程,按顺序进行.的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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