SHARE

Running Worker Thread in C#

Environment: Visual Studio .NET Beta 2, Windows 2000 SP2 .NET framework allows a lot of ways to implement multithreading program. I want to show how we can run worker thread which makes synchronous calls to user interface (for example, thread reads a long recordset and fills some control in the form). To run thread I […]

Written By
thumbnail
CodeGuru Staff
CodeGuru Staff
Jan 29, 2002
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Environment:
Visual Studio .NET Beta 2, Windows 2000 SP2

.NET framework allows a lot of ways to implement multithreading program. I want
to show how we can run worker thread which makes synchronous calls to user
interface (for example, thread reads a long recordset and fills some control
in the form).

To run thread I use:

  • Thread instance and main thread function
  • Two events used to stop thread. First event is set when main thread wants
    to stop worker thread; second event is set by worker thread when it really
    stops.

.NET allows to call System.Windows.Forms.Control functions only from thread
where control was created. To run them from other thread we need to use
Control.Invoke (synchronous call) or Control.BeginInvoke (asynchronous call)
functions. For task like showing database records we need Invoke.
To implement this I use:

  • Delegate type for calling form function, delegate instance and function
    called using this delegate
  • Invoke call from worker thread.

Next problem is to stop worker thread correctly. Steps to do this:

  • Set event “Stop Thread��
  • Wait for event “Thread is stopped”
  • While waiting for event process messages using Application.DoEvents
    function. This prevents deadlock because worker thread makes Invoke calls
    which are processed in main thread.

Thread function checks in every iteration whether Stop Thread event is set.
If event is set, function makes clean-up operations, sets event “Thread is
stopped” and returns.

Demo project has two classes: MainForm and LongProcess. LongProcess.Run
function runs in thread and fills list box with some lines. Worker thread
may finish by natural awy or may be stopped when user presses Stop Thread
button or closes form.

Code fragments:

// MainForm.cs
namespace WorkerThread
{
  // delegates used to call MainForm functions from
  //  worker thread
  public delegate void DelegateAddString(String s);
  public delegate void DelegateThreadFinished();
  public class MainForm : System.Windows.Forms.Form
  {
    …
    // worker thread
    Thread m_WorkerThread;
    // events used to stop worker thread
    ManualResetEvent m_EventStopThread;
    ManualResetEvent m_EventThreadStopped;
    // Delegate instances used to call user interface
    // functions from worker thread:
    public DelegateAddString m_DelegateAddString;
    public DelegateThreadFinished m_DelegateThreadFinished;
    …
    public MainForm()
    {
      InitializeComponent();
      // initialize delegates
      m_DelegateAddString =
           new DelegateAddString(this.AddString);
      m_DelegateThreadFinished =
           new DelegateThreadFinished(this.ThreadFinished);
      // initialize events
      m_EventStopThread = new ManualResetEvent(false);
      m_EventThreadStopped = new ManualResetEvent(false);
    }
    …
    // Start thread button is pressed
    private void btnStartThread_Click(object sender,
                                      System.EventArgs e)
    {
      …
      // reset events
      m_EventStopThread.Reset();
      m_EventThreadStopped.Reset();
      // create worker thread instance
      m_WorkerThread =
          new Thread(new ThreadStart(this.WorkerThreadFunction));
      m_WorkerThread.Name = “Worker Thread Sample”; // looks nice
                                              // in Output window
      m_WorkerThread.Start();
    }
    // Worker thread function.
    // Called indirectly from btnStartThread_Click
    private void WorkerThreadFunction()
    {
      LongProcess longProcess;
      longProcess = new LongProcess(m_EventStopThread,
                                    m_EventThreadStopped, this);
      longProcess.Run();
    }
    // Stop worker thread if it is running.
    // Called when user presses Stop button or form is closed.
    private void StopThread()
    {
      if ( m_WorkerThread != null  &&
           m_WorkerThread.IsAlive )  // thread is active
      {
        // set event “Stop”
        m_EventStopThread.Set();
        // wait when thread  will stop or finish
        while (m_WorkerThread.IsAlive)
        {
          // We cannot use here infinite wait because our thread
          // makes syncronous calls to main form, this will cause
          // deadlock.
          // Instead of this we wait for event some appropriate time
          // (and by the way give time to worker thread) and
          // process events. These events may contain Invoke calls.
          if ( WaitHandle.WaitAll(
              (new ManualResetEvent[] {m_EventThreadStopped}),
              100,
              true) )
          {
              break;
          }
          Application.DoEvents();
        }
      }
    }
    // Add string to list box.
    // Called from worker thread using delegate and Control.Invoke
    private void AddString(String s)
    {
      listBox1.Items.Add(s);
    }
    // Set initial state of controls.
    // Called from worker thread using delegate and Control.Invoke
    private void ThreadFinished()
    {
      btnStartThread.Enabled = true;
      btnStopThread.Enabled = false;
    }
  }
}
// LongProcess.cs
namespace WorkerThread
{
  public class LongProcess
  {
    …
    // Function runs in worker thread and emulates long process.
    public void Run()
    {
      int i;
      String s;
      for (i = 1; i <= 10; i++)
      {
        // make step
        s = “Step number ” + i.ToString() + ” executed”;
        Thread.Sleep(400);
        // Make synchronous call to main form.
        // MainForm.AddString function runs in main thread.
        // To make asynchronous call use BeginInvoke
        m_form.Invoke(m_form.m_DelegateAddString, new Object[] {s});
        // check if thread is cancelled
        if ( m_EventStop.WaitOne(0, true) )
        {
          // clean-up operations may be placed here
          // …
          // inform main thread that this thread stopped
          m_EventStopped.Set();
          return;
        }
      }
      // Make asynchronous call to main form
      // to inform it that thread finished
      m_form.Invoke(m_form.m_DelegateThreadFinished, null);
    }
  }
}

Downloads

Download demo project – 8 Kb

Recommended for you...

C# vs Java
Nicholas Rini
Mar 24, 2023
C# versus C
Nicholas Rini
Mar 22, 2023
Different Types of JIT Compilers in .NET
Tariq Siddiqui
Mar 17, 2023
Middleware in ASP.NET Core
Tariq Siddiqui
Mar 16, 2023
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.