0

I have a Windows Forms app (.NET 2.0) which launches a number of BackgroundWoker threads and handles their ProgressChanged and Completed events when they are updated/finished, respectively. However, I have come across a situation that has me guessing.

I launch BackgroundWorker 1 (BW1), followed by BackgroundWorker 2 (BW2). Let's assume BW1 finishes first and triggers the BackgroundWorkerCompleted event, which the UI thread handles in my event handler ( workerCompleted() ). The event handler takes a while because it calls out to another function.

Now I put a breakpoint at the beginning of the EventHandler and step through a run of the code. While I am stepping through the eventhandler while it is handling BW1, the UI thread suddenly switches to handling BW2.

Eventually the UI thread completes BW1 but I have a race condition that is caused by this unpredictable behavior (in that external function). Thread locking doesn't help because the UI thread ignores the lock the second time (reentrant lock).

Now, if I change the code so that right before the eventhandler calls that external function I place a Application.DoEvents(), it improves (but not totally fixes) the predictable behavior (or I should say, "my" expected behavior).

So, long winded as it may be, should the UI thread be completely finishing one eventhandler before handling the next? Or should I expect that it is non-deterministic?

void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
         // Do some cleanup related things, generate report, etc.
         ...
         // Call some external function to get a value which will increment on next call
         int x = CallExternalFunction();
         // While code is in the above function, UI switches to handling BW2 at the top of this function.  
         // BW2 then calls external function and finishes before BW1 returns
    }

Note, there are no thread related or Application.DoEvents type code int he external function (it is actually just a queue of objects, getting one each time and incrementing an internal counter).

UPDATE: I found my answer. I'm working with code I didn't author, and oversimplified what the external function was doing. I traced and traced it until I found that eventually, it was calling Application.DoEvents which has the effect of interrupting the current eventhandler, and forcing the UI to handle other events.

My apologies for being blind and lazy. Maybe this alone will help someone who finds this later.

Dime
  • 41
  • 5
  • Hmm, dollar to donuts that a "queue of objects" uses a lock. Blocking the UI thread with a lock is illegal, the CLR pumps. Or you are just confused about the way the debugger switches between threads and your second breakpoint is actually inside BW2's DoWork code. – Hans Passant Oct 20 '15 at 22:22
  • There is no lock in the "queue of objects". It's just a list with a current position counter. And I'm positive I'm not breaking in the DoWork. I'm watching the "Threads" window in VS2008 and when this is occuring, there is only one thread present (Main Thread). The only thing that changes in the thread window when BW1 is interrupted is the "Location" column in the threads window which now correctly points to the WorkerCompleted function. Inspecting the object shows that it is indeed BW2. – Dime Oct 21 '15 at 13:56
  • You must post repro code to get help, this isn't it. – Hans Passant Oct 21 '15 at 14:00

0 Answers0