Backgroundworker chokes

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

What happens here?
The backgroundworker (bgw) unzips RTF-Helpfiles (up to 1 MB in size).
The ProgressChanged-Event gets the unzipped files (to display them in a
RichtTextBox)

It follows the Trace that prints always what bgw has unzipped and what
ProgressChanged received:

1. bgw: HelpFilelistgzip
2. ProgressChanged: HelpFilelistgzip OK!
3. bgw: HelpThreadprioritygzip
4. ProgressChanged: HelpThreadprioritygzip OK!
5. bgw: HelpPathgzip
6. bgw: HelpRegexgzip
7. ProgressChanged: HelpRegexgzip NOT OK!!
8. ProgressChanged: HelpRegexgzip

Initially its all good.
But after line 4 (HelpPathgzip) all goes crazy.
bgw works, one after the other, on two separate files (line 5 and 6)
Then ProgressChanged receives TWO times the same unzipped File (lines 7 and 8)

The File in line 5 (HelpPathgzip) is very small (1 kBytes)
The file in line 6 (HelpRegexgzip) is also a nothing (3 kBytes)
In comparison the file in line 1 (HalpFilelistgzip) is enormous (1 MB)

How come that bgw choked?
 
Henry99 said:
What happens here?
The backgroundworker (bgw) unzips RTF-Helpfiles (up to 1 MB in size).
The ProgressChanged-Event gets the unzipped files (to display them in a
RichtTextBox)

It follows the Trace that prints always what bgw has unzipped and what
ProgressChanged received:

1. bgw: HelpFilelistgzip
2. ProgressChanged: HelpFilelistgzip OK!
3. bgw: HelpThreadprioritygzip
4. ProgressChanged: HelpThreadprioritygzip OK!
5. bgw: HelpPathgzip
6. bgw: HelpRegexgzip
7. ProgressChanged: HelpRegexgzip NOT OK!!
8. ProgressChanged: HelpRegexgzip

Initially its all good.
But after line 4 (HelpPathgzip) all goes crazy.
bgw works, one after the other, on two separate files (line 5 and 6)
Then ProgressChanged receives TWO times the same unzipped File (lines 7 and 8)

The File in line 5 (HelpPathgzip) is very small (1 kBytes)
The file in line 6 (HelpRegexgzip) is also a nothing (3 kBytes)
In comparison the file in line 1 (HalpFilelistgzip) is enormous (1 MB)

How come that bgw choked?

I'm afraid I find it fairly tricky to understand what you've written.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
Hi Henry,

As Jon suggested, you can provide us some further code logic about your
application. Also, so far I haven't got any known issue of the
backgroundworker class, so normally we'll first focus on the application
code logic to track down the issue. To make the test easy, if possible, you
can also change the background to do some simplified task or code logic to
see whether the same behavior occur.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi Steven,

thanks for replying.
I've sent the code to (e-mail address removed) on Sunday last.

In all other ocurrencies that I used the Backgroundworker, there was all oK.
And it was also in this same manner with event-driven delegates that I've
programmed. Hmmm
But this was the first time I had to deal with a file of 1.8 MB that is
transferred.
This means: Its pointer.
But the foreground thread (the UI) has to fill an RTF-Box with this 1.8MB.
This seems to point to the guilty part, but, what I dont understand is:
The problem is without doubt reproducible, but every time in another
sequence, so the 1.8 MB shouldnt be the cause.

Yours, Henry
 
Thanks for your followup Henry,

If you got any further progress or result on this, also welcome to share
with us.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi John,

it seems, that you didn't have the time to have a look at the code I've sent
to you.

Here are additional quick-infos to the choking bgw-problem:
Application Example:
A WinFormClient uses the Amazon-API to enlist books in a DataGridView:

- I use a Backgroundworker to get a books-list via SOAP from Amazon
- I report progress using ProgressChangedEventArgs (per query come 10 books
and I report any one book back (not the whole 10 books at a time), to be
responsive)
- I use the UserState-property (which is an object) in this
ProgressChangedEventArgs to send the information from the background-thread
- The foreground-thread (WinForm-UI) receives those updates via the
corresponding event handler (MethodNameProgressChanged) and casts it to the
correct type

Problem:
- The foreground-thread doesn't receive the updates (10 kBytes each, handed
over via UserState) in a clear sequence.

Background sends a sequence: 1, 2, 3, 4, 5
UI receives e.g.: 1, 3, 3, 5, 5
or: 5, 5, 5, 5, 5

Question:
What shall I do to receive the progress reported in sequence?
(E.g. Application.DoEvent or something?)
Or is this method (via UserState) NOT to be used to receive progress other
than a progress-indicator-integer?
Or is the handover too slow, that the background overwrites reference types,
so the foreground receives e.g. 5 times the last one?

When I use Control.CheckForIllegalCrossThreadCalls = False and write
directly from the background-thread to the DataGridView, all comes well in
sequence!!!!
But we shouldn't do this!

Thanks, Heinrich
 
Henry99 said:
it seems, that you didn't have the time to have a look at the code I've sent
to you.

Unfortunately I haven't had time to look at it beyond checking that I
can reproduce it. I'm afraid I'm finding time rather hard to come by at
the moment.
Here are additional quick-infos to the choking bgw-problem:
Application Example:
A WinFormClient uses the Amazon-API to enlist books in a DataGridView:

- I use a Backgroundworker to get a books-list via SOAP from Amazon
- I report progress using ProgressChangedEventArgs (per query come 10 books
and I report any one book back (not the whole 10 books at a time), to be
responsive)
- I use the UserState-property (which is an object) in this
ProgressChangedEventArgs to send the information from the background-thread
- The foreground-thread (WinForm-UI) receives those updates via the
corresponding event handler (MethodNameProgressChanged) and casts it to the
correct type

Problem:
- The foreground-thread doesn't receive the updates (10 kBytes each, handed
over via UserState) in a clear sequence.

Background sends a sequence: 1, 2, 3, 4, 5
UI receives e.g.: 1, 3, 3, 5, 5
or: 5, 5, 5, 5, 5

Aha - yes, it looks like you're using some "global state" to keep track
of what's being sent and received. That's a bad idea, because if the
background thread "sends" two messages by setting the global state and
then invoking a delegate on the main thread (if you see what I mean)
you'll have lost the first piece of information.
Question:
What shall I do to receive the progress reported in sequence?
(E.g. Application.DoEvent or something?)
Or is this method (via UserState) NOT to be used to receive progress other
than a progress-indicator-integer?

It *looks* like UserState is not the way to go here, if you want
distinct messages. It's fine if you *just* want to indicate progress,
where you always want to see the most recent value rather than each
inidividual "message".
Or is the handover too slow, that the background overwrites reference types,
so the foreground receives e.g. 5 times the last one?

It's not really to do with being a reference type. It's just that by
the sounds of it the BackgroundWorker only maintains the most recent
UserState to report.
When I use Control.CheckForIllegalCrossThreadCalls = False and write
directly from the background-thread to the DataGridView, all comes well in
sequence!!!!

That's because you're not using shared state in that case.
But we shouldn't do this!

Indeed you shouldn't.

I'm slightly surprised by the behaviour of UserState in this case - are
you definitely creating a new instance of ProgressChangedEventArgs for
each call? If you're not, that would explain it, certainly.

Basically if you use entirely separate objects each time you call
ReportProgress, I'd expect it to be okay. If it's not, you'll need to
use Control.Invoke/BeginInvoke directly with an appropriate delegate.
 
Hi John,

thanks a lot for your info.
Here comes my update:

Yes, I really instantiated the AmazonUserState each time.
It's like the following

Private Sub bgw1_DoWork( _
ByVal sender As Object, _
ByVal e As DoWorkEventArgs) _
Handles bgwAmazonRequest.DoWork

Dim doProgressArgs As New AmazonUserState
'fill the doProgressArgs, not shown here
bgwAmazonRequest.ReportProgress(0, doProgressArgs)

End Sub

What I've done in the meantime is:

1. Abandoned the Backgroundworker when ProgressReporting is needed
2. Rewritten the whole AmazonClient using Control.Invoke

Nº 2 = THEEE solution.
The App is now running like a clockwork.

Yours Henry99
 
Back
Top