简体   繁体   中英

Waiting for a background worker to finish without blocking UI thread

I have an application that needs to wait for a background worker to finish before moving on. The background worker is in charge of writing some values to a USB device that initializes it. The problem with the background worker is that my main program can try to access the USB device before the background worker is finished initializing.

While the background worker is working, the UI thread shows a "please wait" with an animated progress bar. The progress bar does not reflect how far along the background worker is, it merely 'spins'.

I have read a few questions that say not to use a background worker, because I really don't want it to run asynchronously (which is true), however, without using a background worker, my "please wait" dialog blocks and doesn't show the animation. I have also read a lot that tells me to only use one UI thread, which then supports the use of a background worker.

I have also tried to put the "please wait" spinner in a separate thread, but that introduces complexities and strange race conditions where the "please wait" windows tries to close before it has opened.

What is the right way to go about this?

That's exactly what BackgroundWorker is designed for. Although there are other ways to accomplish this, what you're doing is just fine.

I have read a few questions that say not to use a background worker

Don't really know why people have suggested not to use this as it's exactly what it was designed for. Ideally what you would want to do is show a modal dialog with the spinner and an option to cancel, that way the user is blocked by the UI from interrupting the write process on the USB.

Even simply disabling the buttons during the write process could suffice.

I think there are two separate issues you are trying to resolve.

The first one is how to prevent the Main (UI) thread accessing an uninitialized USB device. The other one is handling the "Please Wait" spinner dialog.

My suggestions are:

  1. Keep the BackgroundWworker handling the USB device initialization.
  2. Add a boolean field to your class, to flag when the USB device completed initialization eg

    private volatile bool _usbDeviceInited = false;

  3. The last thing your background worker will do, is set this flag to true .

  4. Centralize access to the USB device by means of a property. The getter method can inspect the boolean field and return a null value (or raise an exception if you prefer) if USB initialization has not completed.
  5. Modify your code to check if null is being returned (or handle the exception, if you chose to raise one) by the property giving access to the USB device, meaning it is not ready for use. You can handle this condition to alert the user that the USB device is not ready.

The previous steps are one way to solve your first issue. Now, for the spinner.

I suggest suscribing to the RunWorkerCompleted event of your BackgroundWorker . If your BackgroundWorker was created from the main UI thread, the event will fire in the main UIThread (meaning it's safe to interact with the user interface elements). From there you can simply close and dispose your "Please Wait" dialog. You should also check the AsyncCompletedEventArgs.Error property to ensure no error condition was raised from the BackgroundWorker thread while initializing the USB device.

EDIT: I have just read that your app may run a script that immediately tries to access the USB device. Using the pattern I suggested, you may "poll" the property before running the script until it returns a value different than null like this:

bool timedOut = false;
DateTime timeout = DateTime.Now.AddSeconds(timeoutSeconds);
while ( MyClass.MyUsbDevice == null ) {
   if( DateTime.Now > timeout ) {
      timedOut = true;
      break;
   }
   Thread.Sleep(0); // Avoid pegging the CPU, yield it to other processes
}

if( !timedOut ) {
   // run the script
} else {
   // Handle timeout
}

Good Luck!

将必须在BackgroundWorker完成后执行的部分(脚本)放入BackgroundWorkerRunWorkerCompleted事件处理程序中。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM