Geeks With Blogs

News

View Anthony Trudeau's profile on LinkedIn

Add to Technorati Favorites


Anthony Trudeau

I noticed a difference this weekend with how multi-threading works with the Thread class.  Prior to CLR 2.0 you could perform cross-thread operations.  Now, doing so generates an InvalidOperationException with the message “Cross-thread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on.”

Here is the code that will compile on both 1.1 and 2.0, but fails on 2.0 with the aforementioned exception:

public class Form1 : System.Windows.Forms.Form
{
     private System.Windows.Forms.ProgressBar progressBar1;
     private System.Windows.Forms.Button startButton;
     private System.Windows.Forms.Button cancelButton;
     private System.ComponentModel.Container components = null;

     private bool m_cancelled = false;

     // designer code removed for brevity   

     private bool Cancelled
     {
          get { return m_cancelled; }
          set { m_cancelled = value; }
     }

     private void startButton_Click(object sender, System.EventArgs e)
     {
          Cancelled = false;
          startButton.Enabled = false;
          cancelButton.Enabled = true;

          Thread processThread = new Thread(new ThreadStart(ProcessSomething));
          processThread.Start();
     }

     private void cancelButton_Click(object sender, System.EventArgs e)
     {
          Cancelled = true;
     }

     private void ProcessSomething()
     {
          DateTime startTime = DateTime.Now;

          do
          {
              if (Cancelled) break;

              TimeSpan duration = DateTime.Now.Subtract(startTime);
              double totalSeconds = duration.TotalSeconds;
              double percent = totalSeconds / 10 * 100.0;
              int progressPercent = (int)percent;
              progressPercent = (progressPercent > 100 ? 100 : progressPercent);
              progressBar1.Value = progressPercent;
          }
          while (DateTime.Now < startTime.AddSeconds(10));

          startButton.Enabled = true;
          cancelButton.Enabled = false;
     }
}

Now, for the purposes of the progress bar you're okay, because you can use the new BackgroundWorker class.  This class exposes a ProgressChanged and RunWorkerCompleted that should allow you to perform what you need.  The ReportProgress method raises the ProgressChanged event and it has two overloads.  The first simply provides an integer progress value.  But, the second overload adds a state argument that can be any object.

I'm going to look at this a little more.  I have a good idea why Microsoft decided to change the way this works.  But, I think I like being able to shoot myself in the foot if I so choose.  I have mixed feelings on this.

Posted on Sunday, November 6, 2005 3:52 PM | Back to top


Comments on this post: Difference with Threading

# re: Difference with Threading
Requesting Gravatar...
This isn't thread-safe code and should fail, but in 1.1 you can get away with it. It's awesome that MS decided to throw an exception in 2.0 to require thread-safe code. Look for Control.InvokeRequired(), Control.BeginInvoke(), and Control.Invoke(). Calling these static methods allow interaction with a control created on the UI thread from a worker thread. Google for Control.InvokeRequired and you should find a good example.
Left by Mike H on Nov 06, 2005 8:37 PM

# re: Difference with Threading
Requesting Gravatar...
It certainly is not thread-safe code. My point of disagreement is that it shouldn't fail. Thanks for the information on the invoke methods.
Left by Anthony Trudaeu on Nov 07, 2005 4:52 AM

# re: Difference with Threading
Requesting Gravatar...
Sure enough, you can use the invoke methods to call delegates back in the Form or wherever to perform thread-safe cross-thread operations. I did notice that in the 2.0 code my ProcessSomething method seemed to block the UI thread (e.g. I couldn't click the Cancel button) unless I added a line within the loop on the background thread to put the Thread to sleep for a short period of time. Even 5ms seemed to be enough time.
Left by Anthony Trudeau on Nov 07, 2005 6:14 AM

# re: Difference with Threading
Requesting Gravatar...
For Short Fix Use This :

Control.CheckForIllegalCrossThreadCalls = false

Regrads
Left by Reza Ghorbani on Dec 19, 2005 5:38 AM

# re: Difference with Threading
Requesting Gravatar...
Awesome thanks!
Left by Anthony Trudeau on Dec 19, 2005 6:11 AM

Your comment:
 (will show your gravatar)


Copyright © Anthony Trudeau | Powered by: GeeksWithBlogs.net