Multithreading in application, wait till all threads are finished

xdg996678

Member
Joined
Apr 21, 2012
Messages
6
Programming Experience
Beginner
Hi

I have written code as below (well copied from an example)

VB.NET:
             For Each DataRow In dt_Coupon.Rows

                For Each DataRow2 In dt_Markets.Rows

                    Dim oFill_ThreadX As New Match_Thread_Class
                    Dim ThreadX As New Thread(AddressOf oFill_ThreadX.Get_Match)

                    oFill_ThreadX.Match_Title = DataRow(0)

                    ThreadX.Start()

                Next
            Next


(the Match_Thread_Class bit is just so I can pass a few parameters to the thread/function)

I'm trying to make the program run some code after all the threads are finished, but I am unsure of how to.

I have searched quite a bit for a solution but I cannot find one, or cannot understand one to fit my needs

please could you help me?

Many thanks Gary
 
You should not be creating Threads directly for that. You should be using the ThreadPool which will automatically keep the number of concurrent threads to a reasonable level and keep additional tasks queued until a thread becomes available. If you start too many threads you will end up degrading performance, not enhancing it. Also, what exactly is being done in that Get_Match method? If it's very little then, again, you're probably degrading performance. Quite possibly you would be better to use the ThreadPool to queue one task per row in the first table and then have that task compare that row to each row in the second table.

As for the original question, one option would be to set an Integer variable to the number of tasks first up, then decrement that number at the end of each tasks. Each task will then check whether the number is zero and, if it is, it knows that it is the last task and it can then invoke a method back on the UI thread, much like raising an event.
Imports System.Threading

Public Class Form1

    Private taskCount As Integer

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        taskCount = 1000

        For i = 1 To taskCount
            ThreadPool.QueueUserWorkItem(AddressOf DoSomething, i)
        Next
    End Sub

    Private Sub DoSomething(data As Object)
        Console.WriteLine(data.ToString())

        SyncLock Me
            taskCount -= 1

            If taskCount = 0 Then
                BeginInvoke(New MethodInvoker(AddressOf NotifyTasksComplete))
            End If
        End SyncLock

    End Sub

    Private Sub NotifyTasksComplete()
        MessageBox.Show("All tasks completed.")
    End Sub

End Class
The SyncLock is required to make sure that only one thread provides the notification. For instance, let's imagine that all but two tasks are complete and those last two threads are done at just about the same time. The first thread might decrement the counter and then the system switches to the other thread and it also decrements the counter. The count is now zero and so both threads will raise a notification when they test the value of the counter. The SyncLock ensures that no other thread can decrement the counter until the first thread has tested whether it is zero.
 
Hi Thanks for the reply

The Get_Match just parses some information from a webpage, there are a lot of these so it made sence timewise to do then in multiple threads, so I need to pass a URL and some other information to each one.

I'm not sure how I could pass variables to the Sub DoSomething?

Cheers, Gary
 
I'm not sure how I could pass variables to the Sub DoSomething?

Then you should probably read the documentation for the ThreadPool class and its QueueUserWorkItem method. You don't have to wait for information to come to you. You can go get it. If you want to know how a type or member works, the MSDN documentation for that type or member is the obvious first place to find such information.

That said, have you tried running the example code I provided? You might not even need to read the documentation if you do, but even then it wouldn't hurt.
 
Hi Thanks for the reply, the Get_Match is a function, I do not need to get any arguement/parameters back from it, only to pass (multiple criteria) to it initially to run, I've looked at MSDN and I was having trouble understanding, but I will keep plugging away

On your example it only sends the one arguement (i) - I think so anyway!

but maybe I could contacenate the criteria into one and then pull them out in the function?

Thanks, Gary
 
QueueUserWorkItem can only be used to invoke a method that doesn't return a value. As such you must change the implementation of your method or else introduce another method that will call it. You can pass one object to the method but that object can be as complex a you like. It could be an array of collections of DataSets if you wanted.
 
QueueUserWorkItem can only be used to invoke a method that doesn't return a value. As such you must change the implementation of your method or else introduce another method that will call it. You can pass one object to the method but that object can be as complex a you like. It could be an array of collections of DataSets if you wanted.

Thanks for that, I'll go with an array
 
Back
Top