Reputation: 110
I want to know if various threads has finished doing their work and then raise an event, I have the following code:
Private Sub xTask(ByVal Value As String)
Try
Dim th As Thread
For i As Integer = 1 To 254
th = New Thread(Sub() YTask(Value + i))
th.IsBackground = True
th.Start()
Next
'If all threads have finished working, raise an event
Catch ex As Exception
Throw New Exception(ex.Message)
End Try
End Sub
I'm completely new at threading, I'm almost sure that this isn't the best way to do it, could anyone give me some suggestions please?
I'm using Framework 2.0.
Upvotes: 3
Views: 7566
Reputation: 36553
It's very unclear to me what you are really trying to accomplish, so it's hard to recommend a best practice.
But for what you are asking, doing a thread.Join()
on every thread that you start will ensure that you wait for all threads to complete.
See .NET 2.0 doc: https://msdn.microsoft.com/en-us/library/95hbf2ta(v=vs.80).aspx
Your code would then look something like this:
Private Sub xTask(ByVal value As String)
Dim threadList As List(Of Thread) = New List(Of Thread)
For i As Integer = 1 To 254
Dim t = New Thread(Sub() YTask(value))
t.IsBackground = True ' not sure why you want this if you are going to wait for the thread to finish anyways.
t.Start()
threadList.Add(t)
Next
' wait for all threads to finish.
' The loop will only exit once all threads have completed their work.
For Each t In threadList
t.Join()
Next
' Raise event now that all the threads have completed.
End Sub
EDIT: Making the number of threads adjustable
Usually, starting an excessive amount of threads to perform some work is not the best idea. Also depending on how resource intensive each of the thread's work is, it can cause an overall slowdown of your program.
Usually, you want to test which number of threads will give you the proper balance between accomplishing the work faster and in parallel vs. abusing system resources and causing overall performance degradation.
The following code should allow you to easily tune the number of threads to perform your work, and find the right balance for you.
Sub Main()
xTask("192.168.10.")
End Sub
Private Sub xTask(ByVal value As String)
Dim ipAddressesToScan As Queue(Of String) = New Queue(Of String)
SyncLock ipAddressesToScan ' I'm not 100% sure this locking is needed here, but I would do it to be safe, and it doesn't hurt.
For i As Integer = 1 To 254
ipAddressesToScan.Enqueue(value & i)
Next
End SyncLock
Dim threadList As List(Of Thread) = New List(Of Thread)
For i As Integer = 1 To 10 ' <-- change this to whatever number of threads seems to work best for you.
Dim t = New Thread(Sub() YTask(ipAddressesToScan))
't.IsBackground = True ' don't think you need this TBH.
t.Start()
threadList.Add(t)
Next
' Wait for all threads to finish processing the queue.
For Each t In threadList
t.Join()
Next
' Raise event HERE to signal that all the threads have completed.
Console.WriteLine("All threads have finished their work")
End Sub
Private Sub YTask(ByVal ipAddressesToScan As Queue(Of String))
Dim ipAddress As String
Do
SyncLock ipAddressesToScan
If ipAddressesToScan.Count = 0 Then
ipAddress = Nothing
Else
ipAddress = ipAddressesToScan.Dequeue
End If
End SyncLock
If Not String.IsNullOrEmpty(ipAddress) Then
' Perform your scan here...
Console.WriteLine(Thread.CurrentThread.ManagedThreadId & " is scanning IP Address " & ipAddress)
End If
Loop While Not String.IsNullOrEmpty(ipAddress)
End Sub
Upvotes: 3
Reputation: 6399
I would use the Task library for this (assuming you are using .Net 4 upwards).
Add each new task to a list and you can wait for all to finish in one line as shown below:
Private Sub xTask(ByVal Value As String)
Try
Dim task As Task
Dim tasks As New List(Of Task)
For i As Integer = 1 To 254
task = New Task(Sub() YTask(Value))
tasks.Add(task)
task.Start()
Next
' wait up to 5 seconds for all tasks to complete
Task.WaitAll(tasks.ToArray, 5000)
Catch ex As Exception
Throw New Exception(ex.Message)
End Try
End Sub
Upvotes: 3
Reputation: 77934
Well, I think you meant to use BackgroundWorker
here. On completion of the background worker processing (or if it's cancelled) you can raise RunWorkerCompleted
event.
Upvotes: 1