You are on page 1of 17

The article will focus on threading constructs and as such, is meant for both the beginner and those

who pr
thread is a unit of execution. Microsoft has used threads since the Win32 and NT days, and an understandin
any .NET developer. In my limited knowledge, I have assembled a "manual" that could act as a reference fo
using threading in the real world. This section, while part of the article, is only meant to be a basic introduc
The one experienced in threading should overlook it. To create a thread, you must follow these steps:

1. Create a method that takes no arguments and does not return any data.
2. Create a new ThreadStart delegate and specify the method created in step 1.
3. Create a Thread object specifying the ThreadStart object created in step 2.
4. Call ThreadStart to begin execution of the new thread. The code will look something like this:

using System;
using System.Threading;
public class Program
{
    public static void Main()
    {
        ThreadStart operation = new ThreadStart(SimpleWork);
        Thread thr = new Thread(operation);
        thr.Start();
    }
    private static void SimpleWork()
    {
        Console.WriteLine("Thread: {0}",
        Thread.CurrentThread.ManagedThreadId);
    }
}

Here are some of the Thread class's properties:

IsAlive: Gets a value indicating that the current thread is currently executing.


IsBackground: Gets or sets whether the thread runs as a background thread.
IsThreadPoolId: Gets whether this thread is a thread in the thread pool.
ManagedThreadId: Gets a number to identify the current thread.
Name: Gets or sets a name associated with the thread.
Priority: Gets or sets the priority of the thread.
ThreadState: Gets the ThreadState value for the thread.

A more likely scenario than the example shown above is one in which you will want to create multiple threa

using System;
using System.Threading;

public class Program
{
    public static void Main()
    {
        ThreadStart operation = new ThreadStart(SimpleWork);
        for (int x = 1; x <= 5; ++x)
        {
            Thread thr = new Thread(operation);
            thr.Start();
        }
    }
    private static void SimpleWork()
    {
        Console.WriteLine("Thread: {0}", Thread.CurrentThread.ManagedThreadId);
    }
}

Output:

Thread: 3
Thread: 4
Thread: 5
Thread: 6
Thread: 7

Here are some of Thread's methods (not static!!):

Abort: Raises a ThreadAbort exception on the thread to indicate that the thread should be aborted.

Interrupt: Raises a ThreadInterruptException when a thread is in blocked state.

Join: Blocks the calling thread until the thread terminates.

Start: Sets a thread to be scheduled for execution.

Using Thread.Join is sometimes necessary because more often than not, you will need your application to w
execution.

To accomplish this, the Thread class supports the Join method, which is a static method:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading;

class InterruptAwareWorker
{
    private bool interruptRequested;
    private Thread myThread;

    public void Interrupt()
    {
        if (myThread == null)
        interruptRequested = true;
        myThread.Interrupt();
        myThread.Join();
    }

    private void CheckInterrupt()
    {
        if (interruptRequested)
            throw new ThreadInterruptedException();
    }

    public void DoWork(object obj)
    {
        myThread = Thread.CurrentThread;
        try
        {
            while (true)
            {
                // Do some work… (including some blocking operations)
                CheckInterrupt();
                // Do some more work…
                CheckInterrupt();
                // And so forth…
            }
        }

        catch (ThreadInterruptedException)
        {
            // Thread was interrupted; perform any cleanup.
            Console.WriteLine("Thread was interrupted...");
            return;
        }
    }

    public static void Main()
    {
        InterruptAwareWorker w = new InterruptAwareWorker();
        Thread t = new Thread(w.DoWork);
        t.Start();
        // Do some work…
        // Uh-oh, we need to interrupt the worker.
        w.Interrupt();
        t.Join();
    }
}

Output:

Thread was interrupted...

This code runs as a console application in Visual Studio 2010,and therefore will only run on .NET 4.0, yet on
of understanding the concept, here is an example of joining threads:
using System;
using System.Threading;
public class Program
{
    public static void Main()
    {
        int threadCount = 5;
        Thread[] threads = new Thread[threadCount];

        for (int i = 0; i < threadCount; i++)


        {
            int idx = i;
            threads[i] = new Thread(delegate() { Console.WriteLine("Worker {0}", idx); });
        }

        // Now begin execution of each thread using the delegate keyword
        Console.WriteLine("Beginning thread execution...");
        Array.ForEach(threads, delegate(Thread t) { t.Start(); });

        // And lastly join on them (wait for completion):


        Console.WriteLine("Waiting for completion...");
        Array.ForEach(threads, delegate(Thread t) { t.Join(); });
        Console.WriteLine("All threads complete");
    }
}

The result is as expected. Note that when we deal with multiple threads, we need to wait on all our threads
reference to all of our threads and calling Join on each of the threads to wait for the threads to complete:

Beginning thread execution...

Worker 0
Worker 1
Worker 2
Worker 3
Waiting for completion...
Worker 4

All threads complete.

Now in the earlier examples, we were using the ThreadStart delegate, which takes no parameters. In pract
information to individual threads. To do this, you need to use a new delegate called ParamterizedThreadSta
method signature with a single parameter of type Object and returns nothing. Here is an example. Notice th
thread by using this delegate:

using System;
using System.Threading;
public static class Program
{
    public static void Main()
    {
        ParameterizedThreadStart operation =
        new ParameterizedThreadStart(WorkWithParameter);
        Thread theThread = new Thread(operation);
        theThread.Start("hello");
        // a second thread with (data) a different parameter
        Thread newThread = new Thread(operation);
        newThread.Start("goodbye");
    }
    private static void WorkWithParameter(object o)
    {
        string info = (string)o;
        for (int x = 0; x < 10; ++x)
        {
            Console.WriteLine("{0}: {1}", info,
            Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(10);
        }
    }
}

Output:

hello: 3
goodbye: 4
hello: 3
goodbye: 4
hello: 3
goodbye: 4
hello: 3
goodbye: 4
hello: 3
goodbye: 4
goodbye: 4
hello: 3
goodbye: 4
hello: 3
goodbye: 4
hello: 3
hello: 3
goodbye: 4
goodbye: 4
hello: 3

Examine the created method WorkWithParameter(object o). This is a method that takes a single Object par
reference to any object). To use this as the starting point of a thread call, you can create a ParameterizedT
this new method and use the Thread.Start method's overload that takes a single object parameter.

Where this Leads To

The topic of threading can sometimes fog the beginner once he or she enters the topics of synchronization,
like. Let's takes the lock statement. The C# lock statement is really just a shorthand notation for working w
class type. Thus, if you were to look under the hood to see what lock() actually resolves, you would find co

using System;
using System.Threading;

public class WhatIsAThread
{
    private long refCount = 0;
    public void AddRef()
    {
        Interlocked.Increment(ref refCount);
    }

    public void Release()
    {
        if (Interlocked.Decrement(ref refCount) == 0)
        {
            GC.Collect();
        }
    }
}

internal class WorkerClass
{
    public void DoSomeWork()
{

lock(this)
{

for(int i = 0; i < 5; i++)


{
Console.WriteLine("Worker says: " + i + ", ");
}
}
 
// The C# lock statmement is really...
Monitor.Enter(this);
try
{
// Do the work.
For (int i = 0; i < 5; i++)
{
Console.WriteLine("Worker says: " + i + ", ");
}
}
finally
{
Monitor.Exit(this);
}
}
}

public class MainClass
{

    public static int Main(string[] args)
    {
        // Make the worker object.
        WorkerClass w = new WorkerClass();
        Thread workerThreadA = new Thread(new ThreadStart(w.DoSomeWork));
        Thread workerThreadB = new Thread(new ThreadStart(w.DoSomeWork));
        Thread workerThreadC = new Thread(new ThreadStart(w.DoSomeWork));
        workerThreadA.Start();
        workerThreadB.Start();
        workerThreadC.Start();

        return 0;
    }
}

Output:

Worker says: 0,
Worker says: 1,
Worker says: 2,
Worker says: 3,
Worker says: 4,
Worker says: 0,
Worker says: 1,
Worker says: 2,
Worker says: 3,
Worker says: 4,
Worker says: 0,
Worker says: 1,
Worker says: 2,
Worker says: 3,
Worker says: 4,

Threads: A Deeper Look

This section of the article will continue to be a reference for threading, but will also include the Operating S
thread can execute. Of the kernel objects, we will then cover the event thread synchronization object. Exam
us better understand how to effectively achieve concurrency and multithreading. The topic of thread creatio
article. We also want to know why threads can cost: stated loosely, threads are expensive. Each thread is p

Thread kernel object: The OS allocates and initializes one of these data structures for each thread create
structure contains a bunch of properties (discussed later in this chapter) that describe the thread. This data
called the thread's context. The context is a block of memory that contains a set of the CPU's registers. Wh
machine with an x86 CPU, the thread's context uses about 700 bytes of memory. For x64 and IA64 CPUs, t
2,500 bytes of memory, respectively.
Thread environment block (TEB): The TEB is a block of memory allocated and initialized in user mode (a
code can quickly access). The TEB consumes 1 page of memory (4 KB on x86 and x64 CPUs, 8 KB on an IA
head of the thread's exception-handling chain. Each try block that the thread enters inserts a node in the h
removed from the chain when the thread exists the try block. In addition, the TEB contains the thread's thr
some data structures for use by the Graphics Device Interface (GDI) and OpenGL graphics.

User-mode stack: The user-mode stack is used for local variables and arguments passed to methods. It a
indicating what the thread should execute next when the current method returns. By default, Windows alloc
thread's user-mode stack.

Kernel-mode stack: The kernel-mode stack is also used when the application code passes arguments to a
Operating System. For security reasons, Windows copies any arguments passed from user-mode code to th
mode stack to the thread's kernel-mode stack. Once copied, the kernel can verify the argument values, and
access the kernel mode stack, the application can't modify the argument values after they have been valida
begins to operate on them. In addition, the kernel calls methods within itself and uses the kernel-mode sta
store a function's local variables, and to store return addresses. The kernel-mode stack is 12 KB when runn
and 24 KB when running on a 64-bit Windows system.

Using multiple threads for a single program can be done to run entirely independent parts of the program a
and is frequently used in server-side applications. Using threads to break one big task down into multiple p
concurrently is called parallelism. Conceptually speaking, a thread is unit of execution - an execution contex
work being performed by a program. Windows must allocate a kernel object for each thread, along with a s
is mapped onto a processor by the Windows thread scheduler, enabling the in-progress work to actually exe
Instruction Pointer that refers to the current executing instruction. "Execution" consists of the processor fet
decoding it, and issuing it, one instruction after the other, from the thread's code. During the execution of s
data will be routinely moved into and out of registers from the attached main memory. While these register
processor, some of the volatile state also belongs to the thread too. If the thread must be paused, this stat
memory so it can be later restored. Doing this enables the same IP fetch, decode, and issue process to pro
was never interrupted. The process of saving or restoring this state from and to the hardware is called a co

Execution Context

As in Windows, each thread in .NET has data associated with it, and that data is usually propagated to new
security information (the IPrinciple and thread identity), the localization strings, and transaction information
default, the execution context flows to helper threads, but this is costly: a context switch is a heavy-weight
execution context, the ExecutionContext class supplies static methods to control the flow of context informa
namespace, there is an ExecutionContext class that allows you to control how a thread's execution context
Here is what the class looks like: 

public sealed class ExecutionContext : IDisposable, ISerializable


{
    [SecurityCritical]
    public static AsyncFlowControl SuppressFlow();
    public static void RestoreFlow();
    public static Boolean IsFlowSuppressed();
    // Less commonly used methods are not shown
}

You can use this class to suppress the flowing of an execution context, thereby improving your application's
gains can be quite substantial for a server application. There is not much performance benefit for a client a
method is marked with the [SecurityCritical] attribute, making it impossible to call in some client applicatio
you should suppress the flowing of execution context only if the helper thread does not need or access the
initiating thread's execution context does not flow to a helper thread, the helper thread will use whatever e
with it. Therefore, the helper thread really shouldn't execute any code that relies on the execution context s
identity). The example shown next is MSDN code, and compiles with warnings on .NET 4.0. It compiles and

using System;
using System.Threading;
using System.Security;
using System.Collections;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Runtime.Remoting.Messaging;

namespace Contoso
{
    class ExecutionContextSample
    {
        static void Main()
        {
            try
            {
                Console.WriteLine("Executing Main in the primary thread.");
                FileDialogPermission fdp = new FileDialogPermission(
                FileDialogPermissionAccess.OpenSave);
                fdp.Deny();
                // Capture the execution context containing the Deny.
                ExecutionContext eC = ExecutionContext.Capture();

                // Suppress the flow of the execution context.


                AsyncFlowControl aFC = ExecutionContext.SuppressFlow();
                Thread t1 = new Thread(new ThreadStart(DemandPermission));
                t1.Start();
                t1.Join();
                Console.WriteLine("Is the flow suppressed? " +
                ExecutionContext.IsFlowSuppressed());
                Console.WriteLine("Restore the flow.");
                aFC.Undo();
                Console.WriteLine("Is the flow suppressed? " +
                ExecutionContext.IsFlowSuppressed());
                Thread t2 = new Thread(new ThreadStart(DemandPermission));
                t2.Start();
                t2.Join();
                // Remove the Deny.
                CodeAccessPermission.RevertDeny();
                // Capture the context that does not contain the Deny.
                ExecutionContext eC2 = ExecutionContext.Capture();
                // Show that the Deny is no longer present.
                Thread t3 = new Thread(new ThreadStart(DemandPermission));
                t3.Start();
                t3.Join();

                // Set the context that contains the Deny.


                // Show the deny is again active.
                Thread t4 = new Thread(new ThreadStart(DemandPermission));
                t4.Start();
                t4.Join();
                // Demonstrate the execution context methods.
                ExecutionContextMethods();
                Console.WriteLine("Demo is complete, press Enter to exit.");
                Console.Read();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
        // Execute the Demand.
        static void DemandPermission()
        {
            try
            {
                Console.WriteLine("In the thread executing a Demand for " +
                "FileDialogPermission.");
                new FileDialogPermission(
                FileDialogPermissionAccess.OpenSave).Demand();
                Console.WriteLine("Successfully demanded " +
                "FileDialogPermission.");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
        static void ExecutionContextMethods()
        {
            // Generate a call context for this thread.
            ContextBoundType cBT = new ContextBoundType();
            cBT.GetServerTime();
            ExecutionContext eC1 = ExecutionContext.Capture();
            ExecutionContext eC2 = eC1.CreateCopy();
            Console.WriteLine("The hash code for the first execution " +
            "context is: " + eC1.GetHashCode());

            // Create a SerializationInfo object to be used for getting the


            // object data.
            SerializationInfo sI = new SerializationInfo(
            typeof(ExecutionContext),
            new FormatterConverter());

            eC1.GetObjectData(
            sI,
            new StreamingContext(StreamingContextStates.All));
            LogicalCallContext lCC = (LogicalCallContext)sI.GetValue(
            "LogicalCallContext",
            typeof(LogicalCallContext));

            // The logical call context object should contain the previously
            // created call context.
            Console.WriteLine("Is the logical call context information " +
            "available? " + lCC.HasInfo);
        }
    }

    // One means of communicating between client and server is to use the
    // CallContext class. Calling CallContext effectivel puts the data in a thread
    // local store. This means that the information is available to that thread
    // or that logical thread (across application domains) only.
    [Serializable]
    public class CallContextString : ILogicalThreadAffinative
    {
        String _str = "";

        public CallContextString(String str)
        {
            _str = str;
            Console.WriteLine("A CallContextString has been created.");
        }

        public override String ToString()
        {
            return _str;
        }
    }

    public class ContextBoundType : ContextBoundObject
    {
        private DateTime starttime;

        public ContextBoundType()
        {
            Console.WriteLine("An instance of ContextBoundType has been " +
            "created.");
            starttime = DateTime.Now;
        }
        [SecurityPermissionAttribute(SecurityAction.Demand,
        Flags = SecurityPermissionFlag.Infrastructure)]
        public DateTime GetServerTime()
        {
            Console.WriteLine("The time requested by a client.");
            // This call overwrites the client's
            // CallContextString.
            CallContext.SetData(
            "ServerThreadData",
            new CallContextString("This is the server side replacement " +
            "string."));
            return DateTime.Now;
        }
    }
}

Output:

Executing Main in the primary thread.

In the thread executing a Demand for FileDialogPermission.

Successfully demanded FileDialogPermission.

Is the flow suppressed? True

Restore the flow.

Is the flow suppressed? False

In the thread executing a Demand for FileDialogPermission.

Request for the permission of type 'System.Security.Permissions.FileDialogPermis


sion, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e08
9' failed.

In the thread executing a Demand for FileDialogPermission.

Successfully demanded FileDialogPermission.

In the thread executing a Demand for FileDialogPermission.

Successfully demanded FileDialogPermission.

An instance of ContextBoundType has been created.

The time requested by a client.

A CallContextString has been created.

The hash code for the first execution context is: 54267293

Is the logical call context information available? True

Demo is complete, press Enter to exit.

Threads run Within a Process but Processes Don't Run: Threads Run.

Processes in the .NET Framework correspond one to one with a process in Windows. A process' main purpo
resources; this includes a shared virtual address space among all threads running in the process, a HANDLE
DLLs (mapped into the same address space), and a variety of other process-wide data stored in the Process
Problems in one process normally do not affect another because of this type of isolation. However, because
and machine-wide shared resources -- such as files, memory-mapped I/O, and named kernel objects--som
with another process.

Windows provides four objects designed for thread and process synchronization--mutexes, semaphores, ev
objects), and a critical_section object. Events are a kernel synchronization object used to signal other threa
message, has occurred. The important capability offered by events is that multiple threads can be released
a single event is signaled. In .NET, there is an Event class where an event (a type of kernel object) can be
manual reset. When an auto reset event is signaled, the first object waiting for the event turns its back to a
behavior is similar to that of a mutex. Conversely, a manual reset event allows all threads waiting for it to b
manually resets the event to a non-signaled state. These events are represented as the AutoResetEvent cla
.NET. Both of these classes inherit from a common EventWaitHandle class (which itself handles the WaitHan
write some code to schedule some work on the thread-pool:

using System;
using System.Threading;

public sealed class Program
{
    private static void MyThreadPoolWorker(object state)
    {
        ManualResetEvent mre = (ManualResetEvent)state;

        // Do some work; this executes on a thread from the thread-pool...


        Console.WriteLine("Work occurring on the thread-pool: {0}",
        Thread.CurrentThread.ManagedThreadId);

        // Now set the event to let our caller know we're done:
        mre.Set();
    }

    public static void Main()
    {
        using (ManualResetEvent mre = new ManualResetEvent(false))
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(MyThreadPoolWorker), mre);

            // Continue working while the thread-pool executes the work item:
            Console.WriteLine("Continuing work on the main thread: {0}",
            Thread.CurrentThread.ManagedThreadId);

            // Lastly, wait for the thread-pool to finish:


            mre.WaitOne();
        }
    }
}

This example shows registering wait callbacks for events:

using System;
using System.Threading;
public sealed class Program
{
    public static void Main()
    {
        using (EventWaitHandle ewh = new ManualResetEvent(false))
        using (EventWaitHandle callbackDoneEvent = new ManualResetEvent(false))
        {
            // Register our callback to be fired when the event is set:
            ThreadPool.RegisterWaitForSingleObject(ewh,
            delegate
            {
                Console.WriteLine("Callback fired: {0}",
                Thread.CurrentThread.ManagedThreadId);
                callbackDoneEvent.Set();
            }, null, Timeout.Infinite, true);
            // Now set the event. Notice the callback fires
            // on a separate (thread-pool) thread.
            Console.WriteLine("Setting the event: {0}",
            Thread.CurrentThread.ManagedThreadId);
            ewh.Set();

            // wait for the callback to complete


            callbackDoneEvent.WaitOne();
        }
    }
}

The result:

Setting the event: 1


Callback fired: 4
Continuing work on the main thread: 1
Work occurring on the thread-pool: 3

Thread Creation

To create a new thread in the .NET Framework, a Thread object must first be created by of Threadd's many

public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
public class Thread
{
public Thread(ThreadStart start);

public Thread(ThreadStart start, int maxStackSize);

public Thread(ParameterizedThreadStart start);

public Thread(ParameterizedThreadStart start, int maxStackSize);
 
. . . 
}

Recall that a thread created with the ParameterizedThreadStart based constructor allows a caller to pass an
the Start method (as a parameter), which is then accessible from the new thread's Start routine as obj:

//example using delegates

using System;
using System.Threading;

public static class Program
{
    public static void Main()
    {
        Thread newThread = new Thread(
        new ParameterizedThreadStart(MyThreadStart));

        Console.WriteLine("{0}: Created thread (ID {1})",


        Thread.CurrentThread.ManagedThreadId,
        newThread.ManagedThreadId);

        newThread.Start("Hello world"); // Begin execution.

        newThread.Join(); // Wait for the thread to finish.

        Console.WriteLine("{0}: Thread exited",


        Thread.CurrentThread.ManagedThreadId);
    }

    private static void MyThreadStart(object obj)
    {
        Console.WriteLine("{0}: Running: {1}",
        Thread.CurrentThread.ManagedThreadId, obj);
    }
}

The results:

1: Created thread (ID 3)


3: Running: Hello world
1: Thread exited

Here is a thread creation example that uses anonymous delegates:

using System;
using System.Threading;
public static class Program
{
    public static void Main()
    {
        Thread newThread = new Thread(delegate(object obj)
        {
            Console.WriteLine("{0}: Running {1}",
            Thread.CurrentThread.ManagedThreadId, obj);
        });
        newThread.Start("Hello world (with anon delegates)");
        newThread.Join();
    }
}

Output:

3: Running Hello world (with anon delegates)

Finally, here is an example of thread creation using lambdas:

using System;
using System.Threading;

public static class Program
{
    public static void Main()
    {
        Thread newThread = new Thread(obj =>
        Console.WriteLine("{0}: Running {1}",
        Thread.CurrentThread.ManagedThreadId, obj)
        );
        newThread.Start("Hello world (with lambdas)");
        newThread.Join();
    }
}

Output:

3: Running Hello world (with lambdas)

So what have we got? We see that a thread exits. Is the state of the system the same if the thread is abrup
application program will frequently block execution so that it may perform I/O; for example, reading the se
with a network endpoint, etc. But UIs work by processing messages enqueued onto a per-UI-thread messag
blocking enable the UI's message pump to run. But others do not. This can cause messages (e.g., WM_CLO
clogged in the queue until the I/O completes (i.e., it runs synchronously). For lengthy operations, this can l
is an example of a small Windows Forms program that demonstrates the very basics of maintaining the UI:

using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
class Program : Form
{
    private System.Windows.Forms.ProgressBar _ProgressBar;
 
    [STAThread]
    static void Main()
    {
        Application.Run(new Program());
    }
    public Program()
    {
        InitializeComponent();
        ThreadStart threadStart = Increment;
        threadStart.BeginInvoke(null, null);
    }
    void UpdateProgressBar()
    {
        if (_ProgressBar.InvokeRequired)
        {
            MethodInvoker updateProgressBar = UpdateProgressBar;
            _ProgressBar.Invoke(updateProgressBar);
        }
        else
        {
            _ProgressBar.Increment(1);
        }
    }
    private void Increment()
    {
        for (int i = 0; i < 100; i++)
        {
            UpdateProgressBar();
            Thread.Sleep(100);
        }
    }
    private void InitializeComponent()
    {
        _ProgressBar = new ProgressBar();
        SuspendLayout();
        _ProgressBar.Location = new Point(13, 17);
        _ProgressBar.Size = new Size(267, 19);
        ClientSize = new Size(292, 53);
        Controls.Add(this._ProgressBar);
        Text = "Multithreading in Windows Forms";
        ResumeLayout(false);
    }
}

The CLR Thread Pool basics involve queuing up a chunk of work that will be run by the thread pool, use the
asynchronous I/Os complete, execute work on a recurring or timed basis using timers, and/or schedule som
object becomes signaled. There are articles about concurrency at MSDN that describe either managing the
building a custom thread pool to optimize the execution context.

You might also like