|
-
Jun 5th, 2010, 08:26 PM
#1
Thread Starter
Frenzied Member
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:
Imports System.Threading Public Class Form1 Private Elem As String Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load ListBox1.Items.Clear() ThreadPool.QueueUserWorkItem(AddressOf Initialize) End Sub Private Sub Add() Dim pingresult As String pingresult = My.Computer.Network.Ping("192.168.1." & Elem, 200) ListBox1.Items.Add("192.168.1." & Elem & " : " & pingresult) currentIPTextbox.Text = "192.168.1." & Elem Application.DoEvents() End Sub Private Sub Initialize(ByVal State As Object) Dim I As Long SyncLock ListBox1.GetType For I = 1 To 255 Elem = I ListBox1.Invoke(CType(AddressOf Add, MethodInvoker)) Next End SyncLock End Sub End Class
-
Jun 5th, 2010, 08:32 PM
#2
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
-
Jun 5th, 2010, 08:35 PM
#3
Thread Starter
Frenzied Member
Re: Threadpool and Threading in general
not sure what to use for the arguments of those two methods.
-
Jun 5th, 2010, 08:43 PM
#4
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
-
Jun 5th, 2010, 08:47 PM
#5
Thread Starter
Frenzied Member
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?
-
Jun 5th, 2010, 08:49 PM
#6
Re: Threadpool and Threading in general
You are only calling QueueUserWorkItem once
-
Jun 5th, 2010, 08:54 PM
#7
Thread Starter
Frenzied Member
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?
-
Jun 5th, 2010, 08:59 PM
#8
Re: Threadpool and Threading in general
How are you calling QueueUserWorkItem now?
-
Jun 5th, 2010, 09:03 PM
#9
Thread Starter
Frenzied Member
Re: Threadpool and Threading in general
even tried:
vb Code:
For i As Integer = 0 To 3 Dim t As New Thread(AddressOf DoWork) t.Start() Next End Sub Private Sub DoWork() ThreadPool.QueueUserWorkItem(AddressOf Initialize) End Sub
same thing. running consecutively instead of simultaneously
-
Jun 5th, 2010, 09:10 PM
#10
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.
-
Jun 5th, 2010, 09:28 PM
#11
Thread Starter
Frenzied Member
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?
-
Jun 5th, 2010, 09:53 PM
#12
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:
For i = 1 To 255 ThreadPool.QueueUserWorkItem(AddressOf SomeMethod, i) 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.
-
Jun 5th, 2010, 10:05 PM
#13
Thread Starter
Frenzied Member
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
-
Jun 6th, 2010, 11:33 AM
#14
Thread Starter
Frenzied Member
Re: Threadpool and Threading in general
So I've been experimenting with this code:
vb.net Code:
Option Strict On
Imports System.ComponentModel
Imports System.Threading
Public Class Form1
Dim devicesOnlineCount As Integer = 0
Dim devicesOfflineCount As Integer = 0
'delegates used to access the UI.
Public Delegate Sub pingDelegate(ByVal id As String)
Public Delegate Sub pingClassDelegate(ByVal index As Integer, ByVal status As Boolean)
'tracks the number of threads currently running.
Shared threadcount As Integer = 0
'Create a flickerfree listview class.
Public Class FlickerFreeListView
Inherits ListView
Public Sub New()
MyBase.New()
Me.DoubleBuffered = True
End Sub
End Class
Dim lv As New FlickerFreeListView
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'setup the listivew.
With lv
.Dock = System.Windows.Forms.DockStyle.Fill
.UseCompatibleStateImageBehavior = False
.View = View.List
.Columns.Add("IP Address", 100)
End With
Me.mainPanel.Controls.Add(lv)
threadcount = 0
Controls_Lock()
Me.lv.Items.Clear()
lv.Refresh()
filllv()
Try
Ping_Threadpool()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
'Populates the listview with IP range
Private Sub filllv()
Dim i As Integer
Dim xitem As ListViewItem
'load the listview
For i = 1 To 255
xitem = lv.Items.Add("192.168.1." & i)
Next
lv.Refresh()
End Sub
Private Sub Ping_Threadpool()
Dim i As Integer
For i = 1 To lv.Items.Count
'create class
Dim cping As New classPing
'setup class for each ping
cping.index = i
cping.host = lv.Items(i - 1).Text
cping.pingDelegate = AddressOf pingdone
'track thread count
Interlocked.Increment(threadcount)
Try
'Assign each ping to a threadpool.
ThreadPool.QueueUserWorkItem(AddressOf cping.ping)
Catch ex As Exception
MsgBox(ex.Message)
End Try
Next
End Sub
Private Class classPing
Public host As String
Public index As Integer
Public pingDelegate As pingClassDelegate
Public Sub ping(ByVal callback As Object)
Dim pingreply As Boolean
'ping host
Try
pingreply = My.Computer.Network.Ping(host, 200)
'Call delegate sub and send back results
pingDelegate(index, pingreply)
Catch ex As Exception
'do nothing
End Try
End Sub
End Class
'delegate sub called from the thread
Private Sub pingdone(ByVal index As Integer, ByVal result As Boolean)
If lv.InvokeRequired Then
lv.Invoke(New pingClassDelegate(AddressOf PingResult), New Object() {index, result})
Else
PingResult(index, result)
End If
End Sub
'PingResult runs on the UI thread, but is called via a delegate so it is allowed to update the control.
Public Sub PingResult(ByVal index As Integer, ByVal result As Boolean)
Dim itemcolor As Color
'Displays Success in Green and everything else in red
If result Then
itemcolor = Color.Green
Else
itemcolor = Color.Red
End If
lv.Items(index - 1).ForeColor = itemcolor
devicesOfflineLabel.Text = CStr(devicesOfflineCount + 1) 'This only works once
'If threads are all done, begin new scan
If Interlocked.Decrement(threadcount) = 0 Then
threadcount = 0
Controls_Lock()
Me.lv.Items.Clear()
lv.Refresh()
filllv()
Try
Ping_Threadpool()
Catch ex As Exception
MsgBox(ex.Message)
End Try
'Controls_UnLock()
End If
End Sub
Private Sub Controls_Lock()
Me.cmdPing.Enabled = False
Me.Refresh()
End Sub
Private Sub Controls_UnLock()
Me.cmdPing.Enabled = True
Me.Refresh()
End Sub
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.
-
Jun 9th, 2010, 05:39 PM
#15
Thread Starter
Frenzied Member
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|