I have a problem with background worker. I don't know how exactly to describe it. Actually its a game and with the background worker ever x milisecs i update the progress bar and check if anyone has lost/won or the time is up. If someome has win the game ends. If both players have lost/time is up the game goes to the next round. The ploblem occurs when both players have lost. The method NextRound in the SetTime method, runs twice. Here is the code:
void bw_ProgressChanged( object sender, ProgressChangedEventArgs e )
{
this.SetTime(e.ProgressPercentage);
}
void bw_DoWork( object sender, DoWorkEventArgs e )
{
Thread.Sleep(3000);
BackgroundWorker worker = sender as BackgroundWorker;
int tick=ProgLib.maxTime*10;
for( int i = 1; i <= 100; i++ )
{
if( ( worker.CancellationPending == true ) )
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
Thread.Sleep(tick);
worker.ReportProgress(i);
}
}
}
private void SetTime( double k )
{
this.time.Bar1.Value=k;
this.time.Bar2.Value=k;
}
Pravesh Singh
24-Sep-2013There's a threading race in your code. Your worker will call ReportProgress() and immediately iterate the loop. Racing past the CancellationPending property check and falling asleep again.
Your SetTime() method runs later. And calls CancelAsync() but that doesn't have any effect at all since the worker is sleeping. Not until it wakes up again, calls ReportProgress() again, iterates the loop and then sees CancellationPending set to true.
Your SetTime() method will be called again, even though you've already ended the game.
Threading is rife with problems like this. A band-aid is to check for CancellationPending after the Sleep() call. Which works 99.999% of the time. Getting to 100% requires a pretty drastic rewrite that uses proper locking.