0

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
Joshm
  • 31
  • 5
  • Please show us the `show` method aswell. – Visual Vincent Jan 25 '17 at 16:58
  • @VisualVincent I'm assuming there is a problem there, because I'm not exactly sure what you mean. I create Show in the thread itself. `Dim show As New PingPublicDel(AddressOf PingPublicTH)` – Joshm Jan 25 '17 at 18:12
  • Oh, I didn't see that it was a variable (I'm currently at my phone). I found the problem and have written an answer. – Visual Vincent Jan 25 '17 at 19:19
  • @VisualVincent The answer worked perfectly, thank you very much for your time! – Joshm Jan 25 '17 at 20:07
  • Glad I could help! -- I just made an update to the `InvokeIfRequired` extension (the parameters weren't working properly before) and it is _**VERY IMPORTANT**_ that you update your code aswell (just do a copy-paste of mine, it's the first code block). – Visual Vincent Jan 25 '17 at 20:46
  • Sorry for the trouble and for troubling you, but I had to make yet another update to the same code block (apparently I can't catch a break from problems today). Please copy-paste again. -- **This is the last one, I promise.** :) – Visual Vincent Jan 25 '17 at 21:01
  • I've never introduced custom parameters in that extension method before, that's why I'm having a bit of trouble... It is working correctly now. – Visual Vincent Jan 25 '17 at 21:04

1 Answers1

2

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.

Community
  • 1
  • 1
Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
  • Please note that I wrote this answer from my phone. If it doesn't work for you I'll test it as soon as I can. – Visual Vincent Jan 25 '17 at 19:28
  • Thanks! I required 4.5x for the install, I'll incorporate the answer as soon as I can and let you know the result. Thank you so much for your time. – Joshm Jan 25 '17 at 19:38