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



我遇到了一个多线程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

现在,如果您的目标是.NETFramework4.0(或更高版本),您可以使用lambda表达式快速生成内联委托:

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)

但是,如果您的目标是.NETFramework3.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委托,如果您只需要使用一个整数来更新所有线程的状态。

请参阅AndAndAlso之间的差异

最新更新