Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

A Multi-threading Example

4.49/5 (34 votes)
26 Sep 2007CPOL3 min read 2   4.6K  
An Example Showing How to Run Multiple Codes Concurrently and Prevent Cross-thread Operation Errors Using C#
Screenshot - project.jpg

Introduction

You might have wanted to execute several codes concurrently on Windows Forms, but you may encountered the Cross-Thread Operation error or faced your application in a dead mood. There are several ways of preventing the application from hanging. Here, I just want to show a simple way to beginners of how it is easy to achieve such a goal in a very straightforward way.

A couple of months ago, I wanted to start ProgressBar while at the same time doing something else within my application. So, the idea of multi-threading came up. Surely you have to separate the tasks using thread philosophy and also get the application away from hanging. I found some useful articles on the net that allowed me to complete my task successfully. Now I just want to disclose this little experience with those who have the same problem.

Here are some helpful links that I used:

Into the Code

First of all, we define a thread variable in the body of the class. We want it to be global because of further changing on it.

C#
using System.Threading; 
...
public Thread thread = null; //assign a default value Delete 

Delete

Here is the main part for performing our aim. This is contrived in the Delete button. As you see below, first we have defined the thread variable as a global one. For stopping and starting this thread later on, the pause/continue button is used. In our sample in the Delete button, we really don't delete files in the path browsed by the user. It is just a demo for depicting something like that (concurrent code execution is far more important).

C#
private void Btn_Delete_Click(object sender,EventArgs e)
 {
  if(textBox1.Text ==String.Empty)
   {
     MessageBox.Show("Please specify a path");
     return;
   }
     Btn_Pause.Enabled     = true;
     Btn_Stop.Enabled      = true;
     Btn_Delete.Enabled    = false;
     InitializeMyObjects();
     GetAllFiles();   

     thread = new Thread(delegate()
     {
       //Divide thread into several parts.You can execute multiple code 
       //within a thread back to back:

       //Part 1:

//for(int i=0;i<files.Count;Interlocked.Increment(ref i))-for 
//understanding atomic operation see <a href="http://www.albahari.com/">www.albahari.com </a>        
                
        for(int i = 0; i < files.Count; i++)
        {
          //accessing any member out of this thread for changing it 
          //here causes Cross_Thread Opertaion Error.
          //this.Text ="something";//---->Cross_Thread Operation Error(Do 
          //not put here)

          this.BeginInvoke((ThreadStart)delegate()
          {
              this.Text = files[i].ToString().Substring(files[i].LastIndexOf(
                  '\\') + 1);
              //you can delete file by yourself.  
              this.label2.Text = Convert.ToString(i + 1);               
              progressBar1.PerformStep();
          });
        Thread.Sleep(6);
        }
          //Part 2:
          this.BeginInvoke((ThreadStart)delegate()    
          {
              this.Btn_Pause.Enabled = false;
              this.Btn_Stop.Enabled  = false;
          });
         
          //Part 3:
              this.BeginInvoke((ThreadStart)delegate()
          {
              this.ShowMessageDelegate("100% (Process Compeletd)");
          });
     });//.Start();
  thread.Start();  
          
//Implement other codes here for performing them at the time the progressbar 
//is being processed .
 //e.g;
 MessageBox.Show("Am being displayed while progressbar is being performed....");
}

Pause/Continue

Screenshot - pause.jpg

The Pause button also acts as a Continue button for continuing and pausing the thread.

C#
private void Btn_Pause_Click(object sender,EventArgs e)
 {
  if(thread ==null || !thread.IsAlive)
  {
     MessageBox.Show("Process has not been started or just being finished");
     return;
  }
  if(Btn_Pause.Text.ToUpper() == "pause".ToUpper())
  {
     Btn_Pause.Text = "Continue";
     thread.Suspend();
  }
else 
  {
     Btn_Pause.Text = "Pause";
     thread.Resume();
  }
 }

Stop

For stopping a thread, you have to check whether this thread is being suspended or not. If so, make it resume and then abort it. Here, we also implement the rolling back of the progress bar in a new thread.

C#
private void Btn_Stop_Click(object sender,EventArgs e)
{
 if(thread.IsAlive)
  {
     if(thread.ThreadState ==ThreadState.Suspended)
      {
           thread.Resume();
      }

      thread.Abort();
      label2.Text = "THIS PROCESS OF DELETING HAS BEEN ABORTED";
      label2.Refresh();

     new Thread(delegate()
      {
         int val = this.progressBar1.Value;  //--->Don't make mistake,you 
                                             //can read but you can not change 
                                             //if you put any code that wants 
                                             //to modify an object other than 
                                             //this thread you'll see 
                                             //error.<---
          for(int i = 1; i <= val; Interlocked.Increment(ref i))
          {
             this.BeginInvoke((ThreadStart)delegate()
              {
                  progressBar1.Increment(-1);
              });
           Thread.Sleep(10);
          }
      }).Start();
  }
 else 
     label2.Text = "PROCESS HAS BEEN ABORETD";

     Btn_Pause.Enabled      =false;
     Btn_Delete.Enabled     =false;
     Btn_Pause.Text         ="Pause";
     Btn_Stop.Enabled       =false;
     return;
}

Points of Interest

When I made the progress bar run, I noticed that I couldn't drag the form because it hung. So, I began multi-threading for that aim. I used this code for accessing the objects in the same Windows Form by a new thread. When I first created the new thread and then wanted to call a void function for starting some tasks associated with the objects in my form, I got error the error, "Cross-thread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on."

Of course, even in this way if you use objects (write on/modify an object) other than the objects in the new thread — or you have created within the main thread of the application — you will again get this error. You have to use it under the this.BeginInvoke((ThreadStart)delegate(){//implement your logic here...}); part and make the whole new thread start.

Conclusion

All in all, as I mentioned in the introduction, there would be several ways to do this. I used this way because I think it is easy to understand the relevant conceptions and is also very straightforward. By the way, I'd like to ask you to be lenient with my article because it is my first article on the Code Project.

History

  • 26 September, 2007 -- Original version posted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)