Results 1 to 9 of 9

Thread: [RESOLVED] Threading / Delegates

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    Resolved [RESOLVED] Threading / Delegates

    I'm getting myself really confused.

    The idea is to Ping all the addresses in a given Class C sub-net and analyse the responses. Doing this synchronously takes a long time so I thought I'd use the Threading capability of VB2008 to start a new thread to Ping each Address, using Delegates to start the thread and process the results.
    Code:
    Public Class Form1
        Private Delegate Sub DoResult(ByVal pr As PingReply)
        Private Delegate Sub StartPing(ByVal IPCNumber As Integer)
        Private IPSubNet As String
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            IPSubNet = "192.168.1"
            For IPCounter As Integer = 0 To 254
                Dim myPing As StartPing = AddressOf DoPing
                Dim PingParam As Integer = IPCounter
                myPing.Invoke(PingParam)
            Next
        End Sub
    
        Public Sub ShowResult(ByVal pr As PingReply)
            Debug.Print("Address: " + pr.Address.ToString + " Status: " + pr.Status.ToString)
        End Sub
    
        Public Sub DoPing(ByVal ipn As Integer)
            Dim IPToPingC As String = IPSubNet + ipn.ToString
            Dim PingOp As New Ping
            Dim Pingresult As PingReply = PingOp.Send(IPToPingC)
            Dim ADResult As New DoResult(AddressOf ShowResult)
            ADResult.Invoke(Pingresult)
        End Sub
    End Class
    The above is failing with a Null Exception at ' Debug.Print("Address: " + pr.Address.ToString + " Status: " + pr.Status.ToString)'
    Having used the Debugger to look at PingResult in DoPing it's Null, I don't understand why? At the point of failure, IPToPingC has a vaule of "192.168.1.10" and nothing is being output to the Debug Window (so what happened to "192.168.1.0" through to "192.168.1.9" is anyones guess) - and I've only just started using VB2008.

    Never having used Threading I think I'm a little (lot) out of my depth, any assistance would be gratefully received.

    EDIT: Now realised that I should perhaps be using DynamicInvoke for starting DoPing and using Object type as the parameter rather than Invoke but it then fails with :
    A first chance exception of type 'System.MissingMemberException' occurred in Microsoft.VisualBasic.dll
    A first chance exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll

    EDIT2: Just realised what the error message means - I have left the final period off the IPSubNet assignment. It now doesn't fail, but I'm getting wierd results
    Code:
    Address: 192.168.1.104 Status: DestinationHostUnreachable
    Address: 192.168.1.1 Status: Success
    Address: 192.168.1.104 Status: DestinationHostUnreachable
    Address: 192.168.1.104 Status: DestinationHostUnreachable
    Address: 192.168.1.104 Status: DestinationHostUnreachable
    Address: 192.168.1.104 Status: DestinationHostUnreachable
    192.168.1.1 is the gateway and 192.168.1.104 is the address of the PC running this code. Obviously there's some sort of re-synchronisation problem or the code is just not doing what I think it should.
    Current stae of the code:
    Code:
    Imports System.Net.NetworkInformation
    Imports System.Threading
    
    Public Class Form1
        Private Delegate Sub DoResult(ByVal pr As PingReply)
        Private Delegate Sub StartPing(ByVal IPAdd As Integer)
        Private IPSubNet As String
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            IPSubNet = "192.168.1."
            For IPCounter As Integer = 0 To 254
                Dim myPing As StartPing = AddressOf DoPing
                Dim PingParam As Integer = IPCounter
                myPing.DynamicInvoke(PingParam)
            Next
        End Sub
    
        Public Sub ShowResult(ByVal pr As PingReply)
            Debug.Print("Address: " + pr.Address.ToString + " Status: " + pr.Status.ToString)
        End Sub
    
        Public Sub DoPing(ByVal ipn As Integer)
            Dim IPToPingC As String = IPSubNet + ipn.ToString
            Dim PingOp As New Ping
            Dim Pingresult As PingReply = PingOp.Send(IPToPingC)
            Dim ADResult As New DoResult(AddressOf ShowResult)
            ADResult.Invoke(Pingresult)
        End Sub
    End Class
    Last edited by Doogle; May 27th, 2012 at 12:31 AM. Reason: Added EDIT 2

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,222

    Re: Threading / Delegates

    You're making this more difficult than it needs to be. The Ping class already handles the multi-threading for you via its SendAsync method. You simply call SendAsync in a loop and then have a single method to handle the PingCompleted event for each call.

    I've never used it so I don't know whether PingCompleted is raised on the UI thread or the background thread. I'd guess the background thread but you can determine that by testing. If it is the background thread then you simply need to use the ISynchronizeInvoke implementation of your form or else a SynchronizationContext.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3

    Thread Starter
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    Re: Threading / Delegates

    Thanks for the response.

    I tried using SendAsync but it appears that you can't issue a second SendAsync request until the previous one has completed. I'll do a littile more research.

    I've also just realised that if the Host is unreachable there will be no address in the result. I'm getting better results by testing the status and only printing when it's zero (ie success). All I have to do now is to put something in to tell me when it's all finished.

  4. #4
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,222

    Re: Threading / Delegates

    Quote Originally Posted by Doogle View Post
    I tried using SendAsync but it appears that you can't issue a second SendAsync request until the previous one has completed. I'll do a littile more research.
    I would assume that that would be the case for a single Ping object but then you simply create multiple Ping objects.
    Quote Originally Posted by Doogle View Post
    I've also just realised that if the Host is unreachable there will be no address in the result. I'm getting better results by testing the status and only printing when it's zero (ie success). All I have to do now is to put something in to tell me when it's all finished.
    SendAsync allows you to pass in an arbitrary object that you will get back in the event handler, which can contain any information that you may need after the fact. That's a standard part of .NET asynchronous patterns. Such parameters and properties usually have names like 'state' or 'userState'.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  5. #5

    Thread Starter
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    Re: Threading / Delegates

    Well, thanks again. I've re-done it using SendAsync and as you rightly pointed out it's much simpler
    Code:
    Imports System.Net.NetworkInformation
    Imports System.Net.Dns
    Imports System.Net
    
    Public Class Form1
        Private PingCount As Integer = 0
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim SubNet As String = "192.168.1."
            For IPAddressCount As Integer = 0 To 254
                Dim MyPing As NetworkInformation.Ping = New NetworkInformation.Ping
                AddHandler MyPing.PingCompleted, AddressOf PingComplete
                Dim IPAddress As String = SubNet + IPAddressCount.ToString
                MyPing.SendAsync(IPAddress, 2000)
            Next
        End Sub
    
        Private Sub PingComplete(ByVal sender As Object, ByVal e As PingCompletedEventArgs)
            PingCount = PingCount + 1
            Dim Reply As PingReply = e.Reply
            If Reply.Status = 0 Then
                Dim DNSEntry As IPHostEntry = GetHostEntry(e.Reply.Address.ToString)
                Debug.Print(e.Reply.Address.ToString + " " + DNSEntry.HostName)
            End If
            If PingCount = 254 Then MsgBox("Finished")
        End Sub
    End Class
    EDIT: Although I still must get my head round the Threading thing.!!
    Last edited by Doogle; May 27th, 2012 at 03:30 AM.

  6. #6
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,222

    Re: Threading / Delegates

    One thing you should add to that code is a bit of cleanup. In the PingCompleted event handler you should use RemoveHandler to detach the event handler and then Dispose the Ping object.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  7. #7

    Thread Starter
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    Re: Threading / Delegates

    I assume I do that after the whole thing has finished, e.g.
    Code:
            If PingCount = LastPing Then
                MsgBox("Finished")
                RemoveHandler MyPing.PingCompleted, AddressOf PingComplete
                MyPing = Nothing
            End If
    (I had to define MyPing at the Form level rather than in the Button's Click event)
    Last edited by Doogle; May 27th, 2012 at 05:09 AM.

  8. #8
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,222

    Re: Threading / Delegates

    No, not after the whole thing has finished. You are creating one Ping object for every iteration of your loop so you have to cleanup every single one of those objects. There will be one event raised for every object so you have to cleanup in the event handler every time. As with all event handlers, the 'sender' parameter is the object that raised the event, i.e. the Ping object. That's how you access the object, not a member variable:
    vb.net Code:
    1. Dim myPing = DirectCast(sender, Ping)
    2.  
    3. RemoveHandler myPing.PingCompleted, AddressOf PingComplete
    4. myPing.Dispose()
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  9. #9

    Thread Starter
    PowerPoster
    Join Date
    Jul 2006
    Location
    Maldon, Essex. UK
    Posts
    6,334

    Re: Threading / Delegates

    Ah, I'm beginning to see it clearly now ! Thanks.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width