ozat
ozat

Reputation: 110

How to know if a set of threads has finished

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

Answers (3)

sstan
sstan

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

James Harcourt
James Harcourt

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

Rahul
Rahul

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

Related Questions