Threading with .NET 01 July 2003 at 00:00
Threads are very easy to use with C#. In this example I use a thread to ensure that a connection to a database is closed correctly (merely closing a connection in a method was not always successful as that connection was sometimes still busy when the Close() method line was processed).
  // this is the public method called to close the connection
  public void CloseConnection() {
    // create a new thread instance providing the name of the threaded method
    Thread t = new Thread(new ThreadStart(CloseConnectionThread));
    t.Start();
  }
	
  // private method which actual controls the threaded attemps to close the 
  // database connection
  private void CloseConnectionThread() {
    Boolean closed = false;
    String delim = "-------------------------------------------------------";
    int i = 0;  // counter to prevent deadlock
    while(!closed) {
      try {
        // attempt to close the connection again
        connADO.Close();
        Console.WriteLine("Connection closed.");
        closed = true;
      }
      catch (System.Exception se) {
        // increment counter variable
        i++;
        // after 1000 iteration stop trying and write error to console
        if (i > 1000) {
          closed = true;
          Console.WriteLine("Failed to close connection after 1000 attempts." + 
		    delim + se.Message + delim);
        }
      }
    }
  }

Threading with components

Threading with components is a little more complicated as method calls cannot be made to components by any thread other than the thread the main form is running in. However, this can be circumvented with the use of delegates. This is depicted in the following example, where a delegate in the BeginInvoke method to pass values to a method which adds nodes to a TreeView control.

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;

namespace matt_test {
	
  // delegate used to pass arguments using the BeginInvoke method
  public delegate void ThreadEventDelegate(object sender, ThreadEventArgs e);
	
  public class test : Form {

    private TreeView tv = null;
    private ThreadEventDelegate onTreeViewElement;
    private bool running = false;

    public test() : base() {
      // initialise the form
      this.Size = new Size(400,400);
      tv = new TreeView();
      tv.Size = new Size(300,300);
      this.Controls.Add(tv);
      Button b = new Button();
      b.Location = new Point(310,20);
      b.Click += new System.EventHandler(this.event_Clicked);
        this.Controls.Add(b);
      // create the delegate
      onTreeViewElement = new ThreadEventDelegate(populateTreeView);
      // show as dialog box
      this.ShowDialog();
    }
  
    // does the actual work of running through the counter 
    private void workMethod() {
      // start updating the treeview
      tv.BeginUpdate();
      tv.Nodes.Clear();
      // loop through items, calling BeginInvoke method which in turns 
      // calls the populateTreeView method
      for (int i=0; i<3000; i++) {
        String str = Convert.ToString(i);
        BeginInvoke(onTreeViewElement, new object[] {
          this, new ThreadEventArgs(str)
          }
        );
      }
      // finish updating
      tv.EndUpdate();
      running = false;
      Console.WriteLine("Parse complete.n");
    }
  
    // populates the tree view adding a node with each BeginInvoke call
    private void populateTreeView(object sender, ThreadEventArgs e)	{
      string s = e.MyProperty;
      TreeNode n = new TreeNode(s);
      tv.Nodes.Add(n);
    }
  
    private void event_Clicked(object sender, System.EventArgs e) {
      // exit if already running
      if (running) return;
      // set parsing flag to true
      Console.WriteLine("Starting parse....");
      running = true;
      // run the thread
      Thread t = new Thread(new ThreadStart(workMethod));
      t.Start();
    }
  
    public static void Main(string[] args) {
      new test();
    }
  }
  
  // event argument class which is used to store info used to build the 
  // nodes
  public class ThreadEventArgs : EventArgs {
  
    public String MyProperty = "";
  
    public ThreadEventArgs(String text) {
      this.MyProperty = text;
    }
  }
}