News:

MyKidsDiary.in :: Capture your kids magical moment and create your Online Private Diary for your kids

Main Menu

Windows Forms and Background Processing

Started by thiruvasagamani, Mar 20, 2009, 10:39 PM

Previous topic - Next topic

thiruvasagamani

Windows Forms and Background Processing

In the last article, we explored starting threads directly for background processing, but settled on using asynchronous delegates to get our worker thread started. Asynchronous delegates have the convenience of syntax when passing arguments and scale better by taking threads from a process-wide, common language runtime-managed pool. The only real problem we ran into was when the worker thread wanted to notify the user of progress. In this case, it wasn't allowed to work with the UI controls directly (a long-standing Win32® UI no-no). Instead, the worker thread has to send or post a message to the UI thread, using Control.Invoke or Control.BeginInvoke to cause code to execute on the thread that owns the controls. These considerations resulted in the following code:
Copy Code

// Delegate to begin asynch calculation of pi
delegate void CalcPiDelegate(int digits);
void _calcButton_Click(object sender, EventArgs e) {
  // Begin asynch calculation of pi
  CalcPiDelegate calcPi = new CalcPiDelegate(CalcPi);
  calcPi.BeginInvoke((int)_digits.Value, null, null);
}

void CalcPi(int digits) {
  StringBuilder pi = new StringBuilder("3", digits + 2);

  // Show progress
  ShowProgress(pi.ToString(), digits, 0);

  if( digits > 0 ) {
    pi.Append(".");

    for( int i = 0; i < digits; i += 9 ) {
      ...
      // Show progress
      ShowProgress(pi.ToString(), digits, i + digitCount);
    }
  }
}

// Delegate to notify UI thread of worker thread progress
delegate
void ShowProgressDelegate(string pi, int totalDigits, int digitsSoFar);

void ShowProgress(string pi, int totalDigits, int digitsSoFar) {
  // Make sure we're on the right thread
  if( _pi.InvokeRequired == false ) {
    _pi.Text = pi;
    _piProgress.Maximum = totalDigits;
    _piProgress.Value = digitsSoFar;
  }
  else {
    // Show progress synchronously
    ShowProgressDelegate showProgress =
      new ShowProgressDelegate(ShowProgress);
    this.BeginInvoke(showProgress,
      new object[] { pi, totalDigits, digitsSoFar });
  }
}


Notice that we have two delegates. The first, CalcPiDelegate, is for use in bundling up the arguments to be passed to CalcPi on the worker thread allocated from the thread pool. An instance of this delegate is created in the event handler when the user decides they wants to calculate pi. The work is queued to the thread pool by calling BeginInvoke. This first delegate is really for the UI thread to pass a message to the worker thread.

The second delegate, ShowProgressDelegate, is for use by the worker thread that wants to pass a message back to the UI thread, specifically an update on how things are progressing in the long-running operation. To shield callers from the details of thread-safe communication with the UI thread, the ShowProgress method uses the ShowProgressDelegate to send a message to itself on the UI thread through the Control.BeginInvoke method. Control.BeginInvoke asynchronously queues work up for the UI thread and then continues on without waiting for the result.

SOurce : MSDN
Thiruvasakamani Karnan