How To test If Multiple Backgroundworkers have completed

curlydog

Well-known member
Joined
Jul 5, 2010
Messages
50
Programming Experience
Beginner
Hi,
I'm trying to develop an application which searches a sql server database. One particular search entered by the user actually sends seven queries to the database. I've designed it so each of the seven queries is conducted in a seperate backgroundworker, so that they run and return their hits concurrently. When the user enters a search term, a routine (runSearch) is called , which in turn causes each seperate backgroundworker to run.

This work fine when the user enters a single search term.

I'm now trying to allow the user to enter multiple search terms in a multiline textbox. I iterate through the lines in the textbox and call runsearch for each line. I assumed that the progam would wait for each call to runsearch to complete, before running the next.

I now find out this is not the case. When I call runSearch, the backgroundworkers are set in motion. The next line in the textbox then calls runSearch again, but the backgroundworkers from the previous calling of runSearch are still running. This throws up an error stating that the backgroundworker is still busy and cannot be called.

I need a way to test that all of the backgroundworkers have completed before running runsearch again. If one or more of the backgroundworkers are still running, I need to wait before calling runSearch.

I'd appreciate any pointers as to how to acheive this. I'm fairly new to VB so sample code/examples would be great.

thanks
Jason
 
If the purpose of the raceclass is simply to provide information to the worker you don't need to preserve all items in an array, you can just create new instances and pass them as you go to the worker. The worker then process them and after that they are gone.

samuelg78 said:
Dim rc As New raceclass
rc = DirectCast(e.Argument, raceclass)
Highlighted here is an error in your code. Why create a new instance here, not use it, and discard it the next code line? That is pointless and only a waste of resources. Correct:
VB.NET:
Dim rc As raceclass = DirectCast(e.Argument, raceclass)
"raceclass" is not a good name for a class, may I suggest you rename it "Race"?
 
I had tried but it still give me "15".

Amended:

Dim rc as new raceclass

For i = 1 To 15
rc.rcNo = i
'Generate a random token to identify each task.
Me.worker.RunWorkerAsync(Guid.NewGuid(), rc)
Next


Private Sub worker_DoWork(sender As Object, e As DoWorkEventArgs) Handles worker.DoWork
Dim rc As raceclass = DirectCast(e.Argument, raceclass)
'Get the token that identifies this task.
Dim token = DirectCast(e.Token, Guid)

'Always print "15"
console.writeline(rc.rcNo)
End Sub
 
What JohnH posted about the cast is absolutely correct, but it has nothing to do with that problem. You've still only got one 'raceclass' object so you've still only got one 'rcNo' property and that property has been set to 15 before any DoWork events are raised.

What's the point of creating one 'raceclass' object and passing it to every worker anyway? If every worker requires a 'raceclass' object then you should be creating a new 'raceclass' object for every worker, not creating one 'raceclass' object and using it over and over. If every worker doesn't require a 'raceclass' object then what's it for? Why not just pass in the Integer value itself?
 
I am passing class instead of the integer bcos i may need to pass in more info beside rcNo in the future. "If every worker requires a 'raceclass' object then you should be creating a new 'raceclass' object for every worker". Pls give me a example. Thks
 
You've already got an example: your own code. You already know how to create a 'raceclass' object because you're already doing it. Now you just need to do it once for each worker, i.e. each iteration of the loop, instead of only once in total. You already know how to do something once for each iteration because you're already doing it.
 
Thks. It working now, but now i will like to report the status after i performed a httpwebrequest from 1 to 15. For simplicity, the url will return the value of querystring i pass in.

Private Sub worker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles worker.DoWork
Dim rc As New RaceClass
rc = DirectCast(e.Argument, RaceClass)
'Get the token that identifies this task.
Dim token = DirectCast(e.Token, Guid)

Dim url as string = 'http://www.testingurl.com?rcNo=' & rc.rcNo
Dim req As HttpWebRequest = DirectCast(WebRequest.Create(URL), HttpWebRequest)
Dim[FONT=Verdana, Arial, Helvetica, sans-serif] response As WebResponse = req.GetResponse()
[/FONT][FONT=Verdana, Arial, Helvetica, sans-serif] Dim[/FONT][FONT=Verdana, Arial, Helvetica, sans-serif] reader As StreamReader = New StreamReader(response.GetResponseStream())[/FONT]
Dim str As String = reader.ReadLine()
Do While str.Length > 0
str = reader.ReadLine()
Loop


Me.worker.ReportProgress(str, 100)

End Sub

Private Sub worker_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles worker.ProgressChanged
Dim str As String = DirectCast(e.Token, String)

Check01_Ltb.Items.Insert(0, String.Format("rcNo: {0}", str))

End Sub


But the return results is:

15
14
13
12
blank
10
9
8
blank
6
5
4
3
2
1

How come "str" displayed blank?
 
If you're saying there is a blank line there, then that was the content of the 'str' variable when you called ReportProgress.
If you mean two of the work task didn't report progress, then it means they didn't successfully complete. You will have to inspect the e.Error in RunWorkerCompleted event handler to see that.
The purpose of ReportProgress/ProgressChanged is to report progress for a single work task, typically percentage or other intermediate notifcation as the task is carried out. In your case you are using it to report task completion, which is what RunWorkerCompleted event is for. To pass task result data use the e.Result property, which you can use in RunWorkerCompleted if the task was not cancelled and didn't error out.
 
Back
Top