CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12
  1. #1
    Join Date
    Jun 2001
    Location
    Melbourne/Aus (C# .Net 4.0)
    Posts
    686

    OnAskForProgressReport - BackgroundWorker

    I have been using BackgroundWorker components recently. I have a long process and through OnReportProgress, every now and again it lets my foreground thread (Form) know how it's doing...

    In some scenarios though, my User may get impatient and demand the BackgroundWorker tell them how it is doing right that moment. They want a [Tell Me!] button.

    Assuming I have a component defined as follows:
    Code:
    public class BackgroundMoveFinder : BackgroundWorker
    {
        //
    }
    What techniques are there for communicating from the foreground thread to the background worker?

    Is this good? What other options are there?

    Code:
    public class BackgroundMoveFinder : BackgroundWorker
    {
        private Boolean _sendProgress = false;
    
        public void TellMe()
        {
            lock (_sendProgress )
            {
                _sendProgress = true;
            }
        }
    
        // then regularly in my RunWorkerAsync...
    
        Boolean fireEvent = false;
    
        lock (_sendProgress )
        {
            if (_sendProgress )
            {
                _sendProgress = false;
                fireEvent = true;
            }
        }
    
        if (fireEvent)
            OnReportProgress(....);
    
        ...
    }
    
    // then call, from the foreground thread
    myMoveFinder.TellMe();
    Also, I'm not 100% sure if that's the best way to lock or even whether locking is required in this case?
    Last edited by rliq; April 30th, 2010 at 01:40 AM.
    Rob
    -
    Ohhhhh.... Old McDonald was dyslexic, E O I O EEEEEEEEEE.......

  2. #2
    Join Date
    Apr 2010
    Posts
    4

    Re: OnAskForProgressReport - BackgroundWorker

    It sounds like it would almost be easier to just report progress more often - that's basically what you're getting at, right? Or have a "basic" versus "verbose" switch for the background worker. So if you have a user sitting at that screen that doesn't care about the nitty gritty, they would sit on the "basic" tab/view/etc. If you have someone that is more interested in the details, they could switch to the "verbose" or "advanced" tab/view/etc.

    Code:
    public void DoSomething()
    {
      OnReportProgress("Starting loop...");
      for(int i = 0; i < 1000; i++)
      {
        if(IsVerboseMode)
          OnReportProgress("Processing element " + i);
      }
    }

  3. #3
    Join Date
    Mar 2005
    Location
    Vienna, Austria
    Posts
    4,538

    Re: OnAskForProgressReport - BackgroundWorker

    Why not simple implement a progressbar to the program always showing the actual state. If you like you additional can show the percentage of how much is already done in the taskbar of the program
    Jonny Poet

    To be Alive is depending on the willingsness to help others and also to permit others to help you. So lets be alive. !
    Using Code Tags makes the difference: Code is easier to read, so its easier to help. Do it like this: [CODE] Put Your Code here [/code]
    If anyone felt he has got help, show it in rating the post.
    Also dont forget to set a post which is fully answered to 'resolved'. For more details look to FAQ's about Forum Usage. BTW I'm using Framework 3.5 and you ?
    My latest articles :
    Creating a Dockable Panel-Controlmanager Using C#, Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7

  4. #4
    Join Date
    Apr 2010
    Posts
    4

    Re: OnAskForProgressReport - BackgroundWorker

    Quote Originally Posted by JonnyPoet View Post
    Why not simple implement a progressbar to the program always showing the actual state. If you like you additional can show the percentage of how much is already done in the taskbar of the program
    Jonny -

    This is basically what the BackgroundWorker is used for. Instead of creating all of the logic to fire off updates to the UI thread, the BackgroundWorker class has it all self contained. So when rliq calls "OnReportProgress", the handling method would do whatever work is needed to update the GUI - increase a progress bar, update a label, etc.

  5. #5
    Join Date
    Mar 2005
    Location
    Vienna, Austria
    Posts
    4,538

    Re: OnAskForProgressReport - BackgroundWorker

    Quote Originally Posted by bscar View Post
    This is basically what the BackgroundWorker is used for. ....
    Hehe.... This sounds like the car is used to count how much kilometers you have driven. I would say, basically backgroundworker as the name already tells us, is used for doing work in the background, during other things in the foreground could be done and the user is still being able to use the programs GUI, But for information of a user the backgroundworker has already implemented all you need to show the progress of your work too.
    Jonny Poet

    To be Alive is depending on the willingsness to help others and also to permit others to help you. So lets be alive. !
    Using Code Tags makes the difference: Code is easier to read, so its easier to help. Do it like this: [CODE] Put Your Code here [/code]
    If anyone felt he has got help, show it in rating the post.
    Also dont forget to set a post which is fully answered to 'resolved'. For more details look to FAQ's about Forum Usage. BTW I'm using Framework 3.5 and you ?
    My latest articles :
    Creating a Dockable Panel-Controlmanager Using C#, Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7

  6. #6
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: OnAskForProgressReport - BackgroundWorker

    Quote Originally Posted by rliq View Post
    Also, I'm not 100% sure if that's the best way to lock or even whether locking is required in this case?
    I would have to read up to check if setting a boolean is an atomic operation, if it isn't, you need to synchronize. At any rate, even if the set operation is atomic, the way you've coded it is the correct way. Adding an extra (critical section) lock isn't going to slow anything down, so no worries even if the boolean operation is atomic.

    As far as doing this at all. Since your customer is asking for a 'right now' button, it indicates to me that the progress you are reporting back to the ui isn't granular enough.

    So in this regard, I agree with JonnyPoet - just report progress back to the UI more frequently. That way, the user doesn't have to wonder where the process is at.

  7. #7
    Join Date
    Jun 2001
    Location
    Melbourne/Aus (C# .Net 4.0)
    Posts
    686

    Re: OnAskForProgressReport - BackgroundWorker

    Thanks for all for all of the input over the weekend. Maybe I should have given the reason for the [Tell Me!] button.

    Imagine my BackgroundWorker is trying to find the best move in a game down to a depth of 20moves ahead (for example). This may take 5 minutes (for example). I want the user (who has gotten bored waiting after 3 minutes) to be able to signal the BackgroundWorker to give him the best move found so far...

    I was actually just asking if they approach for signalling the BackgroundWorker was ok...
    Rob
    -
    Ohhhhh.... Old McDonald was dyslexic, E O I O EEEEEEEEEE.......

  8. #8
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: OnAskForProgressReport - BackgroundWorker

    In that case, I would use an event to trigger the thread to return the best move found so far.

  9. #9
    Join Date
    Jun 2001
    Location
    Melbourne/Aus (C# .Net 4.0)
    Posts
    686

    Re: OnAskForProgressReport - BackgroundWorker

    Arjay,

    So you mean I publish an OnGimmeBestMove event in my primary thread and then subscribe to it from within my BackgroundWorker code?

    Then when the User hits the [Tell me!] button in the primary thread, it fires the OnGimmeBestMove event, which causes the BackgroundWorker (observer), at it's next available opportunity, to fire an OnProgressChanged event, that is picked up by the Primary thread?

    I thought that may be an option, I was just not too sure it was 'allowed' or an overkill.
    Rob
    -
    Ohhhhh.... Old McDonald was dyslexic, E O I O EEEEEEEEEE.......

  10. #10
    Join Date
    Mar 2005
    Location
    Vienna, Austria
    Posts
    4,538

    Re: OnAskForProgressReport - BackgroundWorker

    Quote Originally Posted by rliq View Post
    Arjay,

    So you mean I publish an OnGimmeBestMove event in my primary thread and then subscribe to it from within my BackgroundWorker code?

    Then when the User hits the [Tell me!] button in the primary thread, it fires the OnGimmeBestMove event, ...
    In that case I would use the already existing click event to set a variable (boolean flag) and the backgroundworker in each turn looks for that variable and if that variable is set to true, then he returns an intermediate result, just by use of the progress changed( you can hand over a class there too ) The variable then is set back to 'false' in that case. The progress report easily can be synchronized with other controls than the progress bar, so you are able to show the result in the GUI
    Last edited by JonnyPoet; May 3rd, 2010 at 02:52 AM.
    Jonny Poet

    To be Alive is depending on the willingsness to help others and also to permit others to help you. So lets be alive. !
    Using Code Tags makes the difference: Code is easier to read, so its easier to help. Do it like this: [CODE] Put Your Code here [/code]
    If anyone felt he has got help, show it in rating the post.
    Also dont forget to set a post which is fully answered to 'resolved'. For more details look to FAQ's about Forum Usage. BTW I'm using Framework 3.5 and you ?
    My latest articles :
    Creating a Dockable Panel-Controlmanager Using C#, Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7

  11. #11
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: OnAskForProgressReport - BackgroundWorker

    I didn't explain this very well, by 'Event', I meant a Windows Event:

    Code:
    privatereadonlyAutoResetEvent _tellMeEvent = newAutoResetEvent( false );
    ///<summary>
    /// Event to stop
    ///</summary>
    privatereadonlyAutoResetEvent _stopEvent = newAutoResetEvent( false );


    In your thread proc code, you would check to see if the tellMe event was set. If it is you fire a OnReportProgress (delegate) event indicating that progress was halted due to a tellMe event and use whatever mechanism you have to return the current best move.

    Inside the thread proc, you do something like this:

    Code:
    while( SearchForBestMove( ) )
    {
    
      switch(  WaitHandle.WaitAny(  new[ ]   _tellMeEvent, _stopEvent }, 0 ) )
      {
      case TellMeEventIndex: // 0
        // 
        // Fire the OnReportProgress indicating the tellMe event was set
        // 
    
        break;
      case StopEventIndex:  // 1
        // Stop event set, so exit thread
    return;
      }
       
        // 
        // Fire the OnReportProgress indicating the best move was found
        // 
    }


    The TellMe button handler looks like this:

    Code:
     
    public void TellMe( object sender, EventArgs e )
    {
      _tellMeEvent.Set( );
    }
    Generally I avoid passing 'state' variables between threads (I mean variables which are set in one thread that cause another thread to take some action. To perform this function, I use the Windows Events like ManualResetEvent or AutoResetEvent. I prefer these events to variables because I can use them in a WaitHandle.WaitAny or other synchronization calls and feel it makes the code cleaner.

  12. #12
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: OnAskForProgressReport - BackgroundWorker

    Now that I've mentioned not to use 'state' variables, let's look at a cleaner way of sharing variables between threads. If we ignore the InterlockedExchange methods for a moment let's look at a clean way of sharing an integer between threads.

    In my opinion, the code should strive to encapsulate the thread locking details as much as possible. In other words, code that uses a variable (field, or property) shouldn't need to ever worry about synchronizing the variable. If you force the users of such variable to provide the synchronization, you run into a higher chance that they'll forget to lock the variable.

    So let's look at a Count property.

    First the non-thread safe version
    Code:
     
    private bool _count = 0;
    
     
    public int Count
    {
      get { return _count; }
      set { _count = value; }
    }
    Next, the thread safe version
    Code:
     
    private bool _count = 0;
    
    private readonly object _countLock = new object( );
     
    public int Count
    {
      get
      {
        lock( _countLock )
        {
          return _count;
        }
      }
      set
      {
        lock( _countLock )
        {
          _count = value;
        }
      }
    }
    The benefit to this approach is that you can use the Count property from any thread without worrying about having to lock it.

    Code:
     
    // Thread 1 - setting the property
    this.Count = 5;
     
    // Thread 2 - getting the property
    if( this.Count < 10 )
    {
      // do something
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured