Results 1 to 15 of 15

Thread: Threadpool and Threading in general

  1. #1

    Thread Starter
    Frenzied Member stateofidleness's Avatar
    Join Date
    Jan 2009
    Posts
    1,780

    Threadpool and Threading in general

    whipped up this code real quick which uses a ThreadPool on Form Load to iterate through my subnet and tell me if there's a device communicating at each IP address.

    Works great.

    some questions:
    Why am I able to update BOTH my label at the top AND the listbox, but I'm only using an .Invoke on the Listbox?

    How can I know how many threads are currently being used while that is executing?

    What does the SyncLock do?

    I'm aware some people don't like the use of Application.DoEvents(). Is it ok to be using it in this instance or is there a better practice?

    For those wanting to try it out, drag a Label and a Listbox to a new form. Label is called "currentIPTextbox", Listbox is default name.

    vb.net Code:
    1. Imports System.Threading
    2.  
    3. Public Class Form1
    4.     Private Elem As String
    5.     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    6.         ListBox1.Items.Clear()
    7.         ThreadPool.QueueUserWorkItem(AddressOf Initialize)
    8.     End Sub
    9.  
    10.     Private Sub Add()
    11.         Dim pingresult As String
    12.         pingresult = My.Computer.Network.Ping("192.168.1." & Elem, 200)
    13.         ListBox1.Items.Add("192.168.1." & Elem & " : " & pingresult)
    14.         currentIPTextbox.Text = "192.168.1." & Elem
    15.         Application.DoEvents()
    16.     End Sub
    17.  
    18.     Private Sub Initialize(ByVal State As Object)
    19.         Dim I As Long
    20.         SyncLock ListBox1.GetType
    21.             For I = 1 To 255
    22.                 Elem = I
    23.                 ListBox1.Invoke(CType(AddressOf Add, MethodInvoker))
    24.             Next
    25.         End SyncLock
    26.     End Sub
    27. End Class

  2. #2
    Raging swede Atheist's Avatar
    Join Date
    Aug 2005
    Location
    Sweden
    Posts
    8,018

    Re: Threadpool and Threading in general

    What happens when you call ListBox1.Invoke is that the Add method is executed on the same thread that created the ListBox (the main thread). This thread also happens to be the same that created the Label. This is why you are able to update both the ListBox and the Label from within the Add method.

    As for your second question, you can get the number of available threads by using the GetAvailableThreads function. Compare the number of available worker threads to the maximum number of threads (GetMaxThreads) and you'll have your answer
    Rate posts that helped you. I do not reply to PM's with coding questions.
    How to Get Your Questions Answered
    Current project: tunaOS
    Me on.. BitBucket, Google Code, Github (pretty empty)

  3. #3

  4. #4
    Raging swede Atheist's Avatar
    Join Date
    Aug 2005
    Location
    Sweden
    Posts
    8,018

    Re: Threadpool and Threading in general

    They both take 2 integers, which will have relevant values when the method returns.
    I believe you can ignore the I/O threads (the second argument to those two methods), and you'd end up with something like this:

    Code:
            Dim availableWorkerThreads, maxWorkerThreads As Integer
            Dim activeWorkerThreads As Integer
    
            System.Threading.ThreadPool.GetAvailableThreads(availableWorkerThreads, Nothing)
            System.Threading.ThreadPool.GetMaxThreads(maxWorkerThreads, Nothing)
            activeWorkerThreads = maxWorkerThreads - availableWorkerThreads
    Rate posts that helped you. I do not reply to PM's with coding questions.
    How to Get Your Questions Answered
    Current project: tunaOS
    Me on.. BitBucket, Google Code, Github (pretty empty)

  5. #5

    Thread Starter
    Frenzied Member stateofidleness's Avatar
    Join Date
    Jan 2009
    Posts
    1,780

    Re: Threadpool and Threading in general

    ah ok cool.

    now maybe I'm misunderstanding this or confusing multiple threads with what I'm doing, but as the program runs, it always says 1 active thread. I thought maybe the idea was that it could spawn as many threads as possible and execute the sub that gets called.

    why would it always be 1?

  6. #6
    Raging swede Atheist's Avatar
    Join Date
    Aug 2005
    Location
    Sweden
    Posts
    8,018

    Re: Threadpool and Threading in general

    You are only calling QueueUserWorkItem once
    Rate posts that helped you. I do not reply to PM's with coding questions.
    How to Get Your Questions Answered
    Current project: tunaOS
    Me on.. BitBucket, Google Code, Github (pretty empty)

  7. #7

    Thread Starter
    Frenzied Member stateofidleness's Avatar
    Join Date
    Jan 2009
    Posts
    1,780

    Re: Threadpool and Threading in general

    oooh. im getting all giddy like a little school girl. been wanting to "thread" my IRIS app for a long time but have always been turned off as soon as I start reading up on it. This threadpool thing is awesome.

    so.. i have 5 QueueUserWorkItem lines now and, indeed, the count went up to 5 when running. But, it doesn't appear to have affected the actual number of threads running at the same time as the "performance" is the same and the label still shows one IP at a time, instead of the expected "scrolling" of numbers that you'd expect with more threads.


    EDIT: wow ok, interesting. My output indicates that it is executing each line one at a time, then going to the next QueueUserWorkItem line. So they aren't running simultaneously. How would I accomplish running like 3 at the same time?

  8. #8
    Raging swede Atheist's Avatar
    Join Date
    Aug 2005
    Location
    Sweden
    Posts
    8,018

    Re: Threadpool and Threading in general

    How are you calling QueueUserWorkItem now?
    Rate posts that helped you. I do not reply to PM's with coding questions.
    How to Get Your Questions Answered
    Current project: tunaOS
    Me on.. BitBucket, Google Code, Github (pretty empty)

  9. #9

    Thread Starter
    Frenzied Member stateofidleness's Avatar
    Join Date
    Jan 2009
    Posts
    1,780

    Re: Threadpool and Threading in general

    even tried:

    vb Code:
    1. For i As Integer = 0 To 3
    2.             Dim t As New Thread(AddressOf DoWork)
    3.             t.Start()
    4.         Next
    5.  
    6.     End Sub
    7.  
    8.     Private Sub DoWork()
    9.         ThreadPool.QueueUserWorkItem(AddressOf Initialize)
    10.     End Sub

    same thing. running consecutively instead of simultaneously

  10. #10
    Raging swede Atheist's Avatar
    Join Date
    Aug 2005
    Location
    Sweden
    Posts
    8,018

    Re: Threadpool and Threading in general

    Ah yes now I see what the problem is. How could I have missed it..
    You have a SyncLock statement in the Initialize method. This means that the first thread will get exclusive rights to the lock, and all other threads will have to wait until the first thread has released the lock (At the end of the SyncLock block), and so on...
    While SyncLocks are very good and crucial for parallel solutions, you might want to restructure your code to keep the synclock block as small as possible. Only the things that must not be accessed by several threads at the same time should be inside the SyncLock statement.
    Rate posts that helped you. I do not reply to PM's with coding questions.
    How to Get Your Questions Answered
    Current project: tunaOS
    Me on.. BitBucket, Google Code, Github (pretty empty)

  11. #11

    Thread Starter
    Frenzied Member stateofidleness's Avatar
    Join Date
    Jan 2009
    Posts
    1,780

    Re: Threadpool and Threading in general

    Ah i see.

    I'm trying to change it so that I can ping from 192.168.1.1 - 192.168.1.255 using as many threads as possible, and update the listbox as it does it.

    what i see happening is that, if i put the range 1 - 255 in a For loop, it finishes that loop before calling the next ThreadPool.QueueUserWorkItem

    I tried removing the For loop and just put an incremented variable in that Initialize sub. But then, it only runs as many times as I insert the line ThreadPool.QueueUserWorkItem manually.

    So how would I accomplish this? ping all IP's in that range with as many threads as allowable by the ThreadPool and still update the listbox?

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

    Re: Threadpool and Threading in general

    The idea is that you call QueueUserWorkItem once for each work item. How many work items have you got? 255, right? So you call QueueUserWorkItem 255 times:
    vb.net Code:
    1. For i = 1 To 255
    2.     ThreadPool.QueueUserWorkItem(AddressOf SomeMethod, i)
    3. Next
    In SomeMethod you get the value of i, make an IP address out of it and ping it. That is all you do. The system handles the rest.
    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

  13. #13

    Thread Starter
    Frenzied Member stateofidleness's Avatar
    Join Date
    Jan 2009
    Posts
    1,780

    Re: Threadpool and Threading in general

    well, i've tried that and the result seems to be the equivalent of no threading at all. UI is frozen at load time while that runs.

    I'm currently looking at this guys' code:
    http://pberblog.com/post/2009/07/21/...-in-VBnet.aspx

  14. #14

    Thread Starter
    Frenzied Member stateofidleness's Avatar
    Join Date
    Jan 2009
    Posts
    1,780

    Re: Threadpool and Threading in general

    So I've been experimenting with this code:

    vb.net Code:
    1. Option Strict On
    2. Imports System.ComponentModel
    3. Imports System.Threading
    4.  
    5. Public Class Form1
    6.  
    7.     Dim devicesOnlineCount As Integer = 0
    8.     Dim devicesOfflineCount As Integer = 0
    9.  
    10.     'delegates used to access the UI.
    11.     Public Delegate Sub pingDelegate(ByVal id As String)
    12.     Public Delegate Sub pingClassDelegate(ByVal index As Integer, ByVal status As Boolean)
    13.  
    14.     'tracks the number of threads currently running.
    15.     Shared threadcount As Integer = 0
    16.  
    17.     'Create a flickerfree listview class.
    18.     Public Class FlickerFreeListView
    19.         Inherits ListView
    20.         Public Sub New()
    21.             MyBase.New()
    22.             Me.DoubleBuffered = True
    23.         End Sub
    24.     End Class
    25.  
    26.     Dim lv As New FlickerFreeListView
    27.  
    28.     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    29.  
    30.         'setup the listivew.
    31.         With lv
    32.             .Dock = System.Windows.Forms.DockStyle.Fill
    33.             .UseCompatibleStateImageBehavior = False
    34.             .View = View.List
    35.             .Columns.Add("IP Address", 100)
    36.         End With
    37.         Me.mainPanel.Controls.Add(lv)
    38.  
    39.         threadcount = 0
    40.         Controls_Lock()
    41.         Me.lv.Items.Clear()
    42.         lv.Refresh()
    43.         filllv()
    44.         Try
    45.             Ping_Threadpool()
    46.         Catch ex As Exception
    47.             MsgBox(ex.Message)
    48.         End Try
    49.  
    50.     End Sub
    51.  
    52.     'Populates the listview with IP range
    53.     Private Sub filllv()
    54.         Dim i As Integer
    55.         Dim xitem As ListViewItem
    56.  
    57.         'load the listview
    58.         For i = 1 To 255
    59.             xitem = lv.Items.Add("192.168.1." & i)
    60.         Next
    61.         lv.Refresh()
    62.     End Sub
    63.  
    64.     Private Sub Ping_Threadpool()
    65.         Dim i As Integer
    66.         For i = 1 To lv.Items.Count
    67.             'create class
    68.             Dim cping As New classPing
    69.  
    70.             'setup class for each ping
    71.             cping.index = i
    72.             cping.host = lv.Items(i - 1).Text
    73.             cping.pingDelegate = AddressOf pingdone
    74.  
    75.             'track thread count
    76.             Interlocked.Increment(threadcount)
    77.  
    78.             Try
    79.                 'Assign each ping to a threadpool.
    80.                 ThreadPool.QueueUserWorkItem(AddressOf cping.ping)
    81.             Catch ex As Exception
    82.                 MsgBox(ex.Message)
    83.             End Try
    84.  
    85.         Next
    86.     End Sub
    87.  
    88.     Private Class classPing
    89.         Public host As String
    90.         Public index As Integer
    91.         Public pingDelegate As pingClassDelegate
    92.  
    93.         Public Sub ping(ByVal callback As Object)
    94.             Dim pingreply As Boolean
    95.             'ping host
    96.             Try
    97.                 pingreply = My.Computer.Network.Ping(host, 200)
    98.                 'Call delegate sub and send back results
    99.                 pingDelegate(index, pingreply)
    100.             Catch ex As Exception
    101.                 'do nothing
    102.             End Try
    103.  
    104.         End Sub
    105.     End Class
    106.  
    107.     'delegate sub called from the thread
    108.     Private Sub pingdone(ByVal index As Integer, ByVal result As Boolean)
    109.         If lv.InvokeRequired Then
    110.             lv.Invoke(New pingClassDelegate(AddressOf PingResult), New Object() {index, result})
    111.         Else
    112.             PingResult(index, result)
    113.         End If
    114.     End Sub
    115.  
    116.     'PingResult runs on the UI thread, but is called via a delegate so it is allowed to update the control.
    117.     Public Sub PingResult(ByVal index As Integer, ByVal result As Boolean)
    118.         Dim itemcolor As Color
    119.  
    120.         'Displays Success in Green and everything else in red
    121.         If result Then
    122.             itemcolor = Color.Green
    123.         Else
    124.             itemcolor = Color.Red
    125.         End If
    126.  
    127.         lv.Items(index - 1).ForeColor = itemcolor
    128.         devicesOfflineLabel.Text = CStr(devicesOfflineCount + 1) 'This only works once
    129.         'If threads are all done, begin new scan
    130.         If Interlocked.Decrement(threadcount) = 0 Then
    131.             threadcount = 0
    132.             Controls_Lock()
    133.             Me.lv.Items.Clear()
    134.             lv.Refresh()
    135.             filllv()
    136.             Try
    137.                 Ping_Threadpool()
    138.             Catch ex As Exception
    139.                 MsgBox(ex.Message)
    140.             End Try
    141.             'Controls_UnLock()
    142.         End If
    143.     End Sub
    144.  
    145.     Private Sub Controls_Lock()
    146.         Me.cmdPing.Enabled = False
    147.         Me.Refresh()
    148.     End Sub
    149.     Private Sub Controls_UnLock()
    150.         Me.cmdPing.Enabled = True
    151.         Me.Refresh()
    152.     End Sub
    153. End Class

    It works BEAUTIFULLY, the only problem is, I don't understand how it works lol. Some things I was trying to do were, remove the "classPing" class and substitute it with a simple sub that performs the ping. I was also trying to get other controls to update in addition to the ListView, but it doesn't work. I tried with a label to keep track of the count of online/offline devices, but it only gets updated once.

    The code seems a bit "advanced" with all the delegates and whatnot, and I'm trying to strip it down to bare minimum for learning purposes.

  15. #15

    Thread Starter
    Frenzied Member stateofidleness's Avatar
    Join Date
    Jan 2009
    Posts
    1,780

    Re: Threadpool and Threading in general

    *bump*

    gentlemen, I'm using the above code to ping an IP. works great.
    the delegate thing confuses the hell out of me and I'm trying to add some additional steps to just a ping.
    let's say I wanted to updated a row in a sql database after each ping, how would i add another sub within the classPing Class and have it function as well?

    like i said, the ping works great, but i'm wanting to add some additional steps per thread, but not sure how...

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