|
-
Mar 28th, 2022, 01:16 PM
#1
Thread Starter
Lively Member
Waiting for threaded work method to complete inside a threaded loop
I am using a threaded loop to spawn a work method, and then wait for the work method to complete before cycling another loop iteration. However, when I specify 4 steps in the loop, I am only getting two steps performed. Is there anything fundamentally wrong in this code? Any better way to do this.
Code:
Public AllThreadsDone As New System.Threading.AutoResetEvent(False)
AllThreadsDone.Set
Dim t = New Thread(AddressOf ThreadedLoop)
t.IsBackground = True
t.SetApartmentState(ApartmentState.STA)
threadList.Add(t)
Sub ThreadedLoop()
For j = 0 to 3
Dim t = New Thread(AddressOf DoWork)
t.IsBackground = True
t.SetApartmentState(ApartmentState.STA)
threadList.Add(t)
Dim t = New Thread(AddressOf waitforthreadcompletion)
t.IsBackground = True
t.SetApartmentState(ApartmentState.STA)
t.Start()
AllThreadsDone.WaitOne()
Next j
End Sub
Sub DoWork()
Thread.Sleep(10000
WorkThreadDone.Set()
End Sub
Private Sub waitforthreadcompletion()
Try
retry:
For Each t In threadList
If t.IsAlive = True Then GoTo retry
Next
AllThreadsDone.Set()
Exit Sub
Catch
GoTo retry
End Try
End Sub
Last edited by pel11; Mar 28th, 2022 at 01:19 PM.
-
Mar 28th, 2022, 06:06 PM
#2
Re: Waiting for threaded work method to complete inside a threaded loop
Hi,
I think I'd've used four BackgroundWorkers, using 'BackgroundWorker1_DoWork' to run the first method.
Then use BackgroundWorker1_RunWorkerCompleted to start 'BackgroundWorker2_DoWork' and 'BackgroundWorker2_RunWorkerCompleted' to start BGW3... etc.
Poppa
Along with the sunshine there has to be a little rain sometime.
-
Mar 28th, 2022, 06:07 PM
#3
Re: Waiting for threaded work method to complete inside a threaded loop
You can use the Task class to perform the multi-threading. It has a lot of nice features including methods for waiting on Tasks:-
Code:
Imports System.Threading
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim tasks As New List(Of Task)
tasks.Add(Task.Run(Sub()
DoWork(200, $"Task 1")
End Sub))
tasks.Add(Task.Run(Sub()
DoWork(2000, $"Task 2")
End Sub))
tasks.Add(Task.Run(Sub()
DoWork(100, $"Task 3")
End Sub))
tasks.Add(Task.Run(Sub()
DoWork(2500, $"Task 4")
End Sub))
tasks.Add(Task.Run(Sub()
DoWork(2900, $"Task 5")
End Sub))
tasks.Add(Task.Run(Sub()
DoWork(5000, $"Task 6")
End Sub))
tasks.Add(Task.Run(Sub()
DoWork(7500, $"Task 7")
End Sub))
'Wait for all tasks to be done
Task.WaitAll(tasks.ToArray)
Debug.WriteLine("All tasks have been completed.")
End Sub
Private Sub DoWork(ByVal delay As Integer, ByVal taskName As String)
Thread.Sleep(delay)
Debug.WriteLine($"{taskName} has completed.")
End Sub
End Class
You could use something similar for your looping algorithm.
-
Mar 28th, 2022, 06:11 PM
#4
Re: Waiting for threaded work method to complete inside a threaded loop
 Originally Posted by Poppa Mintin
Hi,
I think I'd've used four BackgroundWorkers, using 'BackgroundWorker1_DoWork' to run the first method.
Then use BackgroundWorker1_RunWorkerCompleted to start 'BackgroundWorker2_DoWork' and 'BackgroundWorker2_RunWorkerCompleted' to start BGW3... etc.
Poppa
This is just my opinion but I really believe people should distance themselves from dinosaurs like BackgroundWorkers to do threading and asynchronous programming. I believe it's better to do it the modern way, through Async/Await and the Task class.
-
Mar 28th, 2022, 10:48 PM
#5
Thread Starter
Lively Member
Re: Waiting for threaded work method to complete inside a threaded loop
FYI, the threads need to be single apartment, so can Tasks handle this or will they throw a UI exception?
-
Mar 28th, 2022, 10:52 PM
#6
Thread Starter
Lively Member
Re: Waiting for threaded work method to complete inside a threaded loop
Need to find out if Tasks won't throw a UI error (when delegates are used), since single apartment threads will not. I can't use for example ThreadPool.QueueUserWorkItem(Sub(state) WorkMethod, t.token) since it results in a lot of UI exceptions.
-
Mar 28th, 2022, 10:57 PM
#7
Thread Starter
Lively Member
Re: Waiting for threaded work method to complete inside a threaded loop
Tasks are not single apartment, since I just tried one instead of a thread, and I received the ActiveX exception related to the UI that "the thread is not single apartment"
-
Mar 29th, 2022, 04:37 AM
#8
Re: Waiting for threaded work method to complete inside a threaded loop
Why does the ApartmentState matter? Are you exposing it COM for use in VBA/VB6 or another COM client?
-
Mar 29th, 2022, 10:51 AM
#9
Thread Starter
Lively Member
Re: Waiting for threaded work method to complete inside a threaded loop
Yes, I am using Microsoft Excel 16.0 Object Library, and the Interop Excel library, which is Active X and passes arguments as COM. Below is a link to a Sept 2021 article at MS on embedding Excel in C#
https://docs.microsoft.com/en-us/dot...nterop-objects
Last edited by pel11; Mar 29th, 2022 at 10:56 AM.
-
Mar 29th, 2022, 02:20 PM
#10
Re: Waiting for threaded work method to complete inside a threaded loop
 Originally Posted by Niya
This is just my opinion but I really believe people should distance themselves from dinosaurs like BackgroundWorkers to do threading and asynchronous programming. I believe it's better to do it the modern way, through Async/Await and the Task class.
I don't agree with that opinion. The point of the BGW is that it has a mechanism built into it to raise an event on the UI thread. When you don't need to do that, then it does make more sense to use Tasks, but if you need to be raising events on the UI thread, doing that with Tasks is a pain.
One isn't superior to the other in all cases. Each has it's place.
My usual boring signature: Nothing
 
-
Mar 29th, 2022, 03:59 PM
#11
Thread Starter
Lively Member
Re: Waiting for threaded work method to complete inside a threaded loop
Thanks, I think that by the time all the excess baggage for a Winforms app is brought into the discussion, the "parameters change", but yes, for straightforward work, Tasks seem like the way to go. I didn't mean to short-change any of the users who answered, but I did present use of single apartment threads. I also have a lot of textboxes updated and a treeview with icons called via delegates from threads - so UI is used an awful lot.
-
Mar 29th, 2022, 08:57 PM
#12
Re: Waiting for threaded work method to complete inside a threaded loop
 Originally Posted by Shaggy Hiker
I don't agree with that opinion. The point of the BGW is that it has a mechanism built into it to raise an event on the UI thread. When you don't need to do that, then it does make more sense to use Tasks, but if you need to be raising events on the UI thread, doing that with Tasks is a pain.
One isn't superior to the other in all cases. Each has it's place.
Eh. I suppose. I only ever used the BGW once. I just found it incredibly clumsy to use. Even with the need to raise events on the UI thread, I still find it cleaner to just use Tasks or Threads purely:-
Code:
Public Class Form1
Private WithEvents _counter As New Counter
Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Await _counter.DoCount(10)
MessageBox.Show("Count finished.")
End Sub
Private Sub _counter_CountTick(sender As Object, e As CountTickEventArgs) Handles _counter.CountTick
Me.Invoke(Sub()
Label1.Text = e.Count.ToString
End Sub)
End Sub
End Class
Public Class Counter
Public Event CountTick As EventHandler(Of CountTickEventArgs)
Public Async Function DoCount(ByVal count As Integer) As Task
Await Task.Run(Sub()
For i = 1 To count
RaiseEvent CountTick(Me, New CountTickEventArgs(i))
Threading.Thread.Sleep(1000)
Next
End Sub)
End Function
End Class
Public Class CountTickEventArgs
Inherits EventArgs
Public Sub New(ByVal c As Integer)
Me.Count = c
End Sub
Public ReadOnly Property Count As Integer
End Class
I donno...I just find this so much more straightforward and flexible.
-
Mar 30th, 2022, 10:49 PM
#13
Thread Starter
Lively Member
Re: Waiting for threaded work method to complete inside a threaded loop
@Niya, thanks a lot. If the loop is not threaded, is there a trick for using something like WaitOne() to ensure all threads are completed? Using WaitOne() in a non-threaded evironment will stop all processing and threads will stop when the code stops on WaitOne(). However if Waiting is used in a threaded loop, the other threads will complete and finish. The problem I am facing is that it seems impossible to wait for thread completion in non-tgreaded code. That is if you simply start 5 threads in a Button1, and wait for threads to complete, somehow, the UI and the threads will lock up. You could launch a task after the thread initiation,vexe ute all the code in Button1, and then the task will notify when threads are completed. However, I need to stop at the bottom of the loop and wait, but the loop can't be threaded?
Tags for this Thread
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
|