Question Background worker not firing it's other 2 events?

J. Scott Elblein

Well-known member
Joined
Dec 14, 2006
Messages
166
Location
Chicago
Programming Experience
10+
I'm having a problem with some background worker code. I call the runworkerasync, dowork runs through it's code apparently fine, and after End Sub, nothing else in the app happens. The progresschanged event does not fire, even though I explicitly call it, neither does the work complete event.

I set the BGW properties right on the control itself when i added it to the form to True (reports progress and supports cancellation)

Here is how I call the BGW from the form:

VB.NET:
                    BackgroundWorker1.RunWorkerAsync()

                    ' Adding a pause to be sure we send all requests (not working)
                    Do Until BackgroundWorker1.IsBusy = False
                        'Debug.Print("BGW is Busy. looping ...")
                        Threading.Thread.Sleep(100)
                    Loop

                    Dim strString As String

I added the loop, because I want to make sure the BGW finishes before the rest of the loop continues, that it's contained in. I set a breakpoint on the Dim strString line, which never breaks either.

Here is the BGW code itself

VB.NET:
    Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork

        If BackgroundWorker1.CancellationPending = False Then

            Dim r As HttpWebResponse
            Dim h As HttpWebRequest
            Dim noCachePolicy As New System.Net.Cache.HttpRequestCachePolicy(System.Net.Cache.HttpRequestCacheLevel.BypassCache)

            Dim Query As String = "http://www.yahoo.com" '& txtstuff.Text

            h = CType(WebRequest.Create(Query), HttpWebRequest) 'use create shared method of webrequest class.  Cast to HTTPWebRequest
            h.KeepAlive = False ' set keepalives
            h.Referer = "http://www.yahoo.com"
            h.CachePolicy = noCachePolicy
            r = CType(h.GetResponse, HttpWebResponse)   ' get the response of the request
            strResponse = New StreamReader(r.GetResponseStream).ReadToEnd

            ' ## Add progressbar change here, where the 0 is?
            'BackgroundWorker1.ReportProgress(0, strResponse)

        End If

    End Sub


Any advice mucho appreciated :)
 
So, the thread that created the BGW control is made to Run the BGW Async but then what do you do with it?

You send it into a loop, keeping it busy.. So how is it to handle the events that are raised?

Remember, the whole idaea of a BGW is to allow a UI thread to start work and then return to idle. BGW enforces that the thread that created it (UI thread) also be the thread to handle the events, because that is why you dont get an "invoke required" exception.. Worker works, raises progress, UI thread handles event raising, UI thread allowed to access UI controls (it made them), no invoke needed.

By keeping the UI thread busy, you never let it handle the events! It cannot split itself into two and go off and handle the events while it is looping.. And of course, it loops until the work finishes by which time there is no more need for the events to be handled (though they ought to all queue up and then occur at once - i dont know if they do or whether the event pump discards events that cannot be handled right now.. It probably does; i know that java coalesces multiple pending events)


Remove that Do Loop and let the UI thread return to its idle state after starting the work.. poor thing! :)



also, not to sound patronising or anything.. but your ReportProgress line of code is actually commented out.. It's not going to run in that state
 
Thanks cjcard :)

Im still trying to wrap my head around the BGW. I was under the impression that the point behind the bgw was that it could run off and completely be autonomous, doing it's own thing and events no matter what else was going on (generally speaking).

Another thing leading me to believe this was when I didn't add the loop, it went on to finish the For Next Loop I have the BGW call in. Which has a counter, so for example, if I had it loop 50 times, and it was in a Try Catch with an ex.message added, it would instantly loop 50 times and just send me messages saying the bgw was busy.

I guess the only way is to rewrite the code somehow so that the DoWork call is the last line of code in the calling thread (ui thread) huh?

btw, I had just commented out the reportprogress line for testing purposes. I forgot to uncomment it while posting :)
 
Thanks cjcard :)

Im still trying to wrap my head around the BGW. I was under the impression that the point behind the bgw was that it could run off and completely be autonomous, doing it's own thing and events no matter what else was going on (generally speaking).
Well, yeah.. It can and it does. That doesnt change the immutable fact that windows controls must be accessed from their own thread and if you keep that thread busy doing useless work, then it isnt free to handle the events that BGW is raising (given that the whole idea of using BGW is that you let the UI thread fall to idle so it can pump window messages and keep the Form responsive

Another thing leading me to believe this was when I didn't add the loop, it went on to finish the For Next Loop I have the BGW call in. Which has a counter, so for example, if I had it loop 50 times, and it was in a Try Catch with an ex.message added, it would instantly loop 50 times and just send me messages saying the bgw was busy.
If someone told you to do 50 different things in the space of a second, I think you might say 49 times "Sorry, no can do; i'm busy" too!

I guess the only way is to rewrite the code somehow so that the DoWork call is the last line of code in the calling thread (ui thread) huh?
Better off thinking about how you do it in the real world. Someone gives you a to-do list and you start at the top. As you work away they might push more things on at the bottom (or somewhere higher up - priority?). Every time you finish one thing you go back to your list and look for the next thing to do. If someone asks you to work, you only work if youre idle, otherwise you say youre busy. Gradually people will ask you "are you busy?" before asking you to work. When you get to the end of the list, you fall idle.

OO as a design paradigm for programs was developed to mimic the real world. You'd be amazed when you start following the notion, just how logical it all becomes!
 
I generally do try to think of OO in real life terms, but this threading stuff .. oyyyy vayyyyy

LOL

I did get it working by putting a doevents in that loop, after you mentioned I was locking up the thread from handling other events, but I'm thinking that's not the "proper" way to do it, and I want to do it "right", so I'm looking for a better way.
 
Pass the BGW the list of work to do and let the background thread loop it. If that list is not ready when you start the worker, use a Queue that the worker can pick from when it is not busy.
 
Interesting, thanks John. the queue is another thing i've not delved into yet. I'll have to look it up. At first glance it seems like another collection that just acts like a stack?
 
Interesting, thanks John. the queue is another thing i've not delved into yet. I'll have to look it up. At first glance it seems like another collection that just acts like a stack?

no, a stack is a stack and a queue is a queue

in the canteen there is a stack of plates and a queue of people waiting for food. Think about the order of consumption of things that are put into the stack and the queue and you will see that the two are very fundamentally different
 
Back
Top