Click here to Skip to main content
11,632,450 members (80,940 online)
Click here to Skip to main content

Worker Threads in C#

, 30 Jul 2001 CPOL 745.4K 11.1K 299
Rate this:
Please Sign up or sign in to vote.
Running worker threads with syncronous calls to Windows controls

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)

Share

About the Author

5678901234
Antarctica Antarctica
No Biography provided

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 5 Pin
Somnath_dutta21-Aug-13 2:12
memberSomnath_dutta21-Aug-13 2:12 
GeneralMy vote of 5 Pin
Franc Morales16-Aug-13 20:20
memberFranc Morales16-Aug-13 20:20 
GeneralMy vote of 5 Pin
davemaster9923-Jun-13 20:38
memberdavemaster9923-Jun-13 20:38 
GeneralMy vote of 5 Pin
AU9-May-12 13:46
memberAU9-May-12 13:46 
GeneralMy vote of 4 Pin
Ali Fakoor7-Oct-11 23:36
memberAli Fakoor7-Oct-11 23:36 
GeneralJust making AddString() threadsafe Pin
qduda16-May-11 21:06
memberqduda16-May-11 21:06 
QuestionGood Template but Needs Example Pin
Fl0wmastr23-Mar-11 4:04
memberFl0wmastr23-Mar-11 4:04 
AnswerRe: Good Template but Needs Example Pin
Alex Fr23-Mar-11 8:00
memberAlex Fr23-Mar-11 8:00 
GeneralMy vote of 3 Pin
Fl0wmastr23-Mar-11 4:01
memberFl0wmastr23-Mar-11 4:01 
Generalmy vote of 5 Pin
Member 330244816-Feb-11 12:11
memberMember 330244816-Feb-11 12:11 
GeneralMy vote of 5 Pin
roland_h11-Jan-11 14:07
memberroland_h11-Jan-11 14:07 
GeneralСпасибо брателло!!! Pin
AlexForex15-Feb-10 1:12
memberAlexForex15-Feb-10 1:12 
GeneralRe: Спасибо брателло!!! Pin
Alex Fr15-Feb-10 8:08
memberAlex Fr15-Feb-10 8:08 
GeneralSir you totally rock! Pin
anshulskywalker8-May-09 6:55
memberanshulskywalker8-May-09 6:55 
GeneralEncapsulated Worker Thread and Threaded Queue Classes Pin
jakolito18-Mar-09 8:16
memberjakolito18-Mar-09 8:16 
GeneralThanks for this wonderful Article. Pin
KSuthar10-Dec-08 11:31
memberKSuthar10-Dec-08 11:31 
GeneralProblem with threads Pin
csjenci25-Aug-07 6:00
membercsjenci25-Aug-07 6:00 
GeneralThanks for the awesome article and requesting for Questions further. Pin
AmarjeetSinghMatharu28-Jul-07 3:45
memberAmarjeetSinghMatharu28-Jul-07 3:45 
GeneralRe: Thanks for the awesome article and requesting for Questions further. Pin
Alex Fr28-Jul-07 6:36
memberAlex Fr28-Jul-07 6:36 
GeneralRe: Thanks for the awesome article and requesting for Questions further. Pin
AmarjeetSinghMatharu28-Jul-07 22:20
memberAmarjeetSinghMatharu28-Jul-07 22:20 
Questionm_form and overload error Pin
Ashley Sanders20-Apr-07 11:21
memberAshley Sanders20-Apr-07 11:21 
GeneralRe: m_form and overload error Pin
Ashley Sanders23-Apr-07 5:35
memberAshley Sanders23-Apr-07 5:35 
GeneralRe: m_form and overload error Pin
mrloki2-Mar-08 10:47
membermrloki2-Mar-08 10:47 
GeneralVery usefull Pin
Dark-Balron3-Apr-07 1:21
memberDark-Balron3-Apr-07 1:21 
Thanks a lot
GeneralGreat Article Pin
steve_randomno219-Jan-07 5:35
membersteve_randomno219-Jan-07 5:35 
GeneralVisual Quick sort Pin
openit14-Dec-06 4:42
memberopenit14-Dec-06 4:42 
QuestionExecution Blocked! Pin
abdulkadir12345612-Sep-06 10:42
memberabdulkadir12345612-Sep-06 10:42 
AnswerRe: Execution Blocked! Pin
Manuel Ricca20-Oct-06 13:06
memberManuel Ricca20-Oct-06 13:06 
GeneralRe: Execution Blocked! Pin
David C Elliott24-Oct-06 17:20
memberDavid C Elliott24-Oct-06 17:20 
GeneralRe: Execution Blocked! Pin
Manuel Ricca30-Oct-06 6:32
memberManuel Ricca30-Oct-06 6:32 
GeneralBusy waiting Pin
aimsoft230-May-06 20:13
memberaimsoft230-May-06 20:13 
GeneralRe: Busy waiting Pin
Alex Fr30-May-06 20:38
memberAlex Fr30-May-06 20:38 
GeneralRe: Busy waiting Pin
Patrick McElwee13-Oct-06 11:24
memberPatrick McElwee13-Oct-06 11:24 
GeneralVery Nice With GREAT Documentation! Pin
FormerlyRPG4-Apr-06 12:16
memberFormerlyRPG4-Apr-06 12:16 
GeneralPerfect coding style (VC++like). Brief and precise Pin
raymondnana6-Jan-06 1:36
memberraymondnana6-Jan-06 1:36 
GeneralGreat Job Pin
smokingbrat8-Dec-05 9:28
membersmokingbrat8-Dec-05 9:28 
GeneralStopping Worker Thread Created Using BeginInvoke Pin
RMGreenley29-Jul-05 10:54
memberRMGreenley29-Jul-05 10:54 
GeneralCreating Controls In Threads Pin
mflefel25-May-05 2:50
membermflefel25-May-05 2:50 
GeneralRe: Creating Controls In Threads Pin
Alex Fr25-May-05 3:06
memberAlex Fr25-May-05 3:06 
GeneralRe: Creating Controls In Threads Pin
mflefel25-May-05 5:47
membermflefel25-May-05 5:47 
GeneralCreating Controls In Threads Pin
Member 50306927-Aug-09 1:41
memberMember 50306927-Aug-09 1:41 
Generaladd Controls with thread Pin
pigobyte4-May-04 7:46
memberpigobyte4-May-04 7:46 
GeneralGreate help to me Pin
itecgo18-Apr-04 19:24
memberitecgo18-Apr-04 19:24 
GeneralNice one Pin
soup17-Oct-03 0:05
membersoup17-Oct-03 0:05 
GeneralInvoke vs. BeginInvoke Pin
Lilly24-Feb-03 7:28
memberLilly24-Feb-03 7:28 
GeneralRe: Invoke vs. BeginInvoke Pin
Alex Farber24-Feb-03 19:25
memberAlex Farber24-Feb-03 19:25 
GeneralAccess to ActiveX control properties and methods Pin
donzocchi21-Feb-02 11:46
memberdonzocchi21-Feb-02 11:46 
GeneralRe: Access to ActiveX control properties and methods Pin
Anonymous17-Jun-04 15:46
sussAnonymous17-Jun-04 15:46 
Generalc/c++ Pin
sandip.j.ajani17-Aug-01 20:00
membersandip.j.ajani17-Aug-01 20:00 
QuestionRe: c/c++ Pin
raghaveni10-Oct-06 7:34
memberraghaveni10-Oct-06 7:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150728.1 | Last Updated 31 Jul 2001
Article Copyright 2001 by 5678901234
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid