|
-
April 30th, 2010, 01:36 AM
#1
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.......
-
April 30th, 2010, 11:59 AM
#2
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);
}
}
-
April 30th, 2010, 12:05 PM
#3
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
-
April 30th, 2010, 12:10 PM
#4
Re: OnAskForProgressReport - BackgroundWorker
 Originally Posted by JonnyPoet
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.
-
April 30th, 2010, 12:53 PM
#5
Re: OnAskForProgressReport - BackgroundWorker
 Originally Posted by bscar
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
-
May 1st, 2010, 11:30 AM
#6
Re: OnAskForProgressReport - BackgroundWorker
 Originally Posted by rliq
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.
-
May 2nd, 2010, 06:59 PM
#7
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.......
-
May 2nd, 2010, 09:54 PM
#8
Re: OnAskForProgressReport - BackgroundWorker
In that case, I would use an event to trigger the thread to return the best move found so far.
-
May 3rd, 2010, 01:59 AM
#9
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.......
-
May 3rd, 2010, 02:46 AM
#10
Re: OnAskForProgressReport - BackgroundWorker
 Originally Posted by rliq
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
-
May 3rd, 2010, 01:23 PM
#11
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.
-
May 3rd, 2010, 01:36 PM
#12
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|