Click here to Skip to main content
6,595,854 members and growing! (18,451 online)
Email Password   helpLost your password?
Languages » C# » Beginners     Beginner License: The Code Project Open License (CPOL)

Worker Threads in C#

By Alex Fr

Running worker threads with syncronous calls to Windows controls
C#, VC6, Windows, .NET 1.0, Dev
Posted:30 Jul 2001
Views:467,779
Bookmarked:215 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
109 votes for this article.
Popularity: 9.37 Rating: 4.60 out of 5
4 votes, 4.0%
1
2 votes, 2.0%
2
2 votes, 2.0%
3
9 votes, 9.0%
4
83 votes, 83.0%
5

Introduction

The .NET framework provides a lot of ways to implement multithreading programs. I want to show how we can run a worker thread which makes syncronous calls to a user interface (for example, a thread that 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 you to call System.Windows.Forms.Control functions only from the thread in which the control was created. To run them from another thread we need to use the Control.Invoke (synchronous call) or Control.BeginInvoke (asynchronous call) functions. For tasks like showing database records we need Invoke.

To implement this we will use:

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

The next problem is to stop the worker thread correctly. The steps to do this are:

  • Set the event "Stop Thread"
  • Wait for the event "Thread is stopped"
  • Wait for the event process messages using the Application.DoEvents function. This prevents deadlocks because the worker thread makes Invoke calls which are processed in the main thread.

The thread function checks every iteration whether the "Stop Thread" event has been set. If the event is set the function invokes clean-up operations, sets the event "Thread is stopped" and returns.

Demo project has two classes: MainForm and LongProcess. The LongProcess.Run function runs in a thread and fills the list box with some lines. The worker thread may finish naturally or may be stopped when user presses the "Stop Thread" button or closes the 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 synchronous call to main form

            // to inform it that thread finished

            m_form.Invoke(m_form.m_DelegateThreadFinished, null);
        }

    }
}

License

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

About the Author

Alex Fr


Member

Occupation: Software Developer
Location: Israel Israel

Other popular C# articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 37 (Total in Forum: 37) (Refresh)FirstPrevNext
GeneralSir you totally rock! Pinmemberanshulskywalker7:55 8 May '09  
GeneralEncapsulated Worker Thread and Threaded Queue Classes Pinmemberjakolito9:16 18 Mar '09  
GeneralThanks for this wonderful Article. PinmemberKSuthar12:31 10 Dec '08  
GeneralProblem with threads Pinmembercsjenci7:00 25 Aug '07  
GeneralThanks for the awesome article and requesting for Questions further. PinmemberAmarjeetSinghMatharu4:45 28 Jul '07  
GeneralRe: Thanks for the awesome article and requesting for Questions further. PinmemberAlex Fr7:36 28 Jul '07  
GeneralRe: Thanks for the awesome article and requesting for Questions further. PinmemberAmarjeetSinghMatharu23:20 28 Jul '07  
Questionm_form and overload error PinmemberAshley Sanders12:21 20 Apr '07  
GeneralRe: m_form and overload error PinmemberAshley Sanders6:35 23 Apr '07  
GeneralRe: m_form and overload error Pinmembermrloki11:47 2 Mar '08  
GeneralVery usefull PinmemberDark-Balron2:21 3 Apr '07  
GeneralGreat Article Pinmembersteve_randomno26:35 19 Jan '07  
GeneralVisual Quick sort Pinmemberopenit5:42 14 Dec '06  
QuestionExecution Blocked! Pinmemberabdulkadir12345611:42 12 Sep '06  
AnswerRe: Execution Blocked! PinmemberManuel Ricca14:06 20 Oct '06  
GeneralRe: Execution Blocked! PinmemberDavid C Elliott18:20 24 Oct '06  
GeneralRe: Execution Blocked! PinmemberManuel Ricca7:32 30 Oct '06  
GeneralBusy waiting Pinmemberaimsoft221:13 30 May '06  
GeneralRe: Busy waiting PinmemberAlex Fr21:38 30 May '06  
GeneralRe: Busy waiting PinmemberPatrick McElwee12:24 13 Oct '06  
GeneralVery Nice With GREAT Documentation! PinmemberFormerlyRPG13:16 4 Apr '06  
GeneralPerfect coding style (VC++like). Brief and precise Pinmemberraymondnana2:36 6 Jan '06  
GeneralGreat Job Pinmembersmokingbrat10:28 8 Dec '05  
GeneralStopping Worker Thread Created Using BeginInvoke PinmemberRMGreenley11:54 29 Jul '05  
GeneralCreating Controls In Threads Pinmembermflefel3:50 25 May '05  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 30 Jul 2001
Editor: Chris Maunder
Copyright 2001 by Alex Fr
Everything else Copyright © CodeProject, 1999-2009
Web22 | Advertise on the Code Project