none
Most appropriate way to send data from main thread to BackgroundWorker thread? RRS feed

  • Question

  • I am just about to try using a BackgroundWorker for the very first time.  What is the most appropriate way to send data from the main thread to the BackgroundWorker thread?

    I see the ProgressChanged event is available to send data back to the main thread, but didn't see anything similar sending data the other way.  I'm also uncertain if I should really be using ProgressChanged for a task that isn't just the update of something like a progress bar.

     

    (In case it turns out I should be taking a completely different approach to multithreading instead of this, here's a brief description of what I was going to attempt:  I have an application that creates/loads thumbnail images to use in a ListView, however generating the thumbnails takes a horribly long time.  I was going to start a single BackgroundWorker on application startup, and have it do the thumbnail creation/loading in the background while the user uses the application.  It would generate a thumbnail or perhaps a very small group of them and periodically report back in ProgressChanged so the main thread can display that thumbnail/group into the UI.  This would repeat either until everything is done or until the user requests a different set of thumbnails, at which point the main thread needs to send a message to the BackgroundWorker to tell it to stop what it's doing and start the new task instead.)

     

    Thanks for any suggestions, pointers to articles about BackgroundWorkers I missed, etc.

    Thursday, April 1, 2010 1:04 AM

Answers

  • Hi,

    - You can pass data (for example the directory being searched) when starting the worker

    - If you make your BW interruptable (setting WorkerSupportsCancellation to true) and your BW periodically checks for CancellationPending, then your main thread can issue a BW.CancelAsync() when it's time to stop the current task. After making sure it really stopped, restart with new data.

    - When reporting progress you can pass back an object (ReportProgress(Int32, Object)) which can contain whatever information the main thread might need.

    The example in the documentation shows the use of these (except passing back an object via progress report, if memory serves).

    Cristian.

    • Marked as answer by sriesch Saturday, April 3, 2010 6:17 PM
    Thursday, April 1, 2010 12:21 PM

All replies

  • Hi,

    - You can pass data (for example the directory being searched) when starting the worker

    - If you make your BW interruptable (setting WorkerSupportsCancellation to true) and your BW periodically checks for CancellationPending, then your main thread can issue a BW.CancelAsync() when it's time to stop the current task. After making sure it really stopped, restart with new data.

    - When reporting progress you can pass back an object (ReportProgress(Int32, Object)) which can contain whatever information the main thread might need.

    The example in the documentation shows the use of these (except passing back an object via progress report, if memory serves).

    Cristian.

    • Marked as answer by sriesch Saturday, April 3, 2010 6:17 PM
    Thursday, April 1, 2010 12:21 PM
  • Hi,

    I hoping that you do know how to start a BackgroundWorker and only not sure of how to send data to it. In that case you can use the overloaded 'RunWorkerAsync' function to send in arguments. This argument is recieved in the 'DoWork' event handler as 'e.Argumnt' where 'e' is 'DoWorkEventArgs' member supplied to this function by the framework. Check MSDN for more details.

    Friday, April 2, 2010 3:12 AM
  • Ok, I think I see now:  CancelAsync() doesn't exit the background worker completely, it just cancels the current task assigned to the background worker, which allows RunWorkerAsync() to be called more than once without raising an error, correct?

    I haven't had a chance to implement it yet, but I think that's what I needed to know.  Thanks everyone!

    Friday, April 2, 2010 11:59 AM
  • I don't believe you can re-use cancelled BGWs, though I haven't actually tried it.

    What I would do is get a producer/consumer queue of sorts, either from .NET 4, Rx, or one of my own. Then have the BGW periodically check it for updates.

           -Steve


    Programming blog: http://nitoprograms.blogspot.com/
      Including my TCP/IP .NET Sockets FAQ
      and How to Implement IDisposable and Finalizers: 3 Easy Rules
    Microsoft Certified Professional Developer

    How to get to Heaven according to the Bible
    Friday, April 2, 2010 12:47 PM
  • CancelAsync() will not exit or cancel anything but it will "request cancellation": it will set the BackgroudWorker´s CancellationPending to true.

    It is your background´s worker job to periodically check CancellationPending and interrupt your processing if true (See the Fibonacci example in the BackgroundWorker documentation)

    You can call RunWorkerAsync() as many times as you like, but only after checking that the previous run really finished (IsBusy = false).

    Schematically it looks like this:

    BW.RunWorkerAsync(someDirectory)
    
    // continue doing other stuff
    
    // user requested some other directory
    
    BW.CancelAsync()
    
    while (BW.IsBusy)
    
    {
    
        // twiddle your thumbs or continue doing some useful stuff
    
    }
    
    BW.RunWorkerAsync(someOtherDirectory)   

    And the worker:

     

    bool DoThumbNails(List<string> thumbNails, 
                                BackgroundWorker worker, 
                                DoWorkEvents e)
    
    {
         for (int i = 0; i < thumbnails.Count; i++)
        {
            if (worker.CancellationPending)
            { e.Cancel = true; break; }
    
             // do thumbnails
         }
         return true;
    }

     

     

     

     

     

     

     

     

    Saturday, April 3, 2010 6:11 PM
  • I am just about to try using a BackgroundWorker for the very first time.  What is the most appropriate way to send data from the main thread to the BackgroundWorker thread?

    I see the ProgressChanged event is available to send data back to the main thread, but didn't see anything similar sending data the other way.  I'm also uncertain if I should really be using ProgressChanged for a task that isn't just the update of something like a progress bar.

     

    (In case it turns out I should be taking a completely different approach to multithreading instead of this, here's a brief description of what I was going to attempt:  I have an application that creates/loads thumbnail images to use in a ListView, however generating the thumbnails takes a horribly long time.  I was going to start a single BackgroundWorker on application startup, and have it do the thumbnail creation/loading in the background while the user uses the application.  It would generate a thumbnail or perhaps a very small group of them and periodically report back in ProgressChanged so the main thread can display that thumbnail/group into the UI.  This would repeat either until everything is done or until the user requests a different set of thumbnails, at which point the main thread needs to send a message to the BackgroundWorker to tell it to stop what it's doing and start the new task instead.)

     

    Thanks for any suggestions, pointers to articles about BackgroundWorkers I missed, etc.


    Why not create a Queue and then pass that to the worker thread?

    The .Net Queue class does not support wait/event support so unfortunately it is not a perfect solution, but is a start.

    Cap'n

     

     

     

    Saturday, April 3, 2010 6:38 PM