2017-01-25 5 views
0

У меня проблема с многопоточными пинсами, которые подвешивают мой основной поток. При отладке проблемы я замечаю, что, когда основной поток зависает, он запускает каждый поток и переходит к следующему для пингов. В основном, он должен ping 5 различных IP-адресов, и если они все вниз, вся моя нить зависает в течение 20-30 секунд. Я использую BeginInvoke, но он все еще не работает правильно.Multi-thread haning up main thread, порядок.

Еще одна особенность заключается в том, что я добавил окно сообщения в конце каждого потока, чтобы посмотреть, как они завершатся. У меня есть 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 
+0

Пожалуйста, покажите нам метод 'show'. –

+0

@VisualVincent Я предполагаю, что там есть проблема, потому что я не совсем уверен, что вы имеете в виду. Я создаю Show в самой ветке. 'Dim show As New PingPublicDel (AddressOf PingPublicTH)' – Joshm

+0

О, я не видел, что это переменная (сейчас я нахожусь на своем телефоне). Я нашел проблему и написал ответ. –

ответ

2

Проблема здесь состоит в том, что вы вызываете одни и те же методы, еще раз, что, как предполагается, для запуска в потоках. Это приводит к тому, что запрос ping будет отправлен еще раз, но на этот раз код работает в потоке пользовательского интерфейса (следовательно, он замораживается). Вы должны убедиться, что вы вызываете только код, обновляющий интерфейс.

Это не является обязательным, но я рекомендую вам использовать 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.

+0

Обратите внимание, что я написал этот ответ с моего телефона. Если это не сработает для вас, я проверю его, как только смогу. –

+0

Спасибо! Мне потребовалось 4,5 раза для установки, я включу ответ, как только смогу, и дам вам знать результат. Большое вам спасибо за ваше время. – Joshm