SIGN UP MEMBER LOGIN:    
ARTICLE

Synchronizing Threads in a Multithreaded Application in .Net - C#

Posted by Amit Choudhary Articles | Visual C# July 26, 2011
Here you will see synchronization of threads in a multithreaded application in .Net.
Reader Level:


The Problem "Concurrency"

When you build a multithreaded application, your program needs to ensure that shared data should be protected from the possibility of multiple thread engagement with its value. What's going to happen if multiple threads were accessing the data at the same point? The CLR can suspend any thread for a while who's going to update the value or is in the middle of updating the value and at same time a thread comes to read that value which is not completely updated, that thread is reading an uncompleted/unstable data.

To illustrate the problem of concurrency let us write some line of code.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("----Synchronnization of Threads-----");
        Console.WriteLine("Main Thread {0}", Thread.CurrentThread.ManagedThreadId);
        Printer p = new Printer();

        Thread[] threads = new Thread[5];

        //Queue 5 threads
        for (int i = 0; i < 5; i++)
        {
            threads[i] = new Thread(new ThreadStart(p.PrintNumbersNonSync));
        }
        foreach (Thread t in threads)
        {
            t.Start();
        }

        Console.ReadLine();
    }
}

class Printer
{
    public void PrintNumbersNonSync()
    {
        Console.WriteLine(" ");
        Console.WriteLine("Executing Thread {0}", Thread.CurrentThread.ManagedThreadId);
        for (int i = 1; i <= 10; i++)
        {
            Console.Write(i + " ");
        }
    }
}


Run this program multiple times and watch the output:

Output 1:

Multithreaded application in .Net

Output 2:

Multithreaded application in .Net

As you can see all the output will vary each time you run the program.

What is happening here is that all the threads are sharing the same object of the Printer class and trying to execute the same function at the same time so every time the shared data is being updated randomly which is an unstable state.

Synchronization of threads Solution to the problem of concurrency

Use the locks whenever there's a Shared section. C# provides a Lock keyword that can be used to lock the section that is being accessed by multiple threads. This is the very basic technique to avoid the instability in a multithreaded environment while programming with C#.

The Lock keyword requires you to specify the token (an object reference) that must be acquired by a thread to enter within the lock scope. In the case of a private method you can lock it down by passing the reference of the current type using the "this" keyword.

For e.g.

public void PrintNumbersSynchronized()
{
    //Synchronization thread
    lock (this)
    {
        Console.WriteLine(" ");
        Console.WriteLine("Executing Thread {0}", Thread.CurrentThread.ManagedThreadId);

        for (int i = 1; i <= 10; i++)
        {
            Console.Write(i + " ");
        }

    }
}


However if you are locking down a region of code within a public member, it is safer (and best practice) to declare a private object member variable to serve as the lock token:

class Printer
{
    // Synchronization token
    private Object ThreadLock = new object();
 
    public void PrintNumbersSynchronized()
    {
        //Synchronization thread
        lock (ThreadLock)
        {
            Console.WriteLine(" ");
            Console.WriteLine("Executing Thread {0}", Thread.CurrentThread.ManagedThreadId);
            for (int i = 1; i <= 10; i++)
            {
                Console.Write(i + " ");
            }

        }
    }
}

Output:

Multithreaded application in .Net

Other methods to perform the synchronization

Monitor is a class in the System.Threading namespace that also provides the same functionality. Actually lock is just a shorthand notation of Monitor class. When the compiler processes a lock it actually resolves to the following:

public void PrintNumbersSync()
{
    Monitor.Enter(ThreadLock);
    try
    {
        Console.WriteLine(" "
);
        Console.WriteLine("Executing Thread {0}", Thread.CurrentThread.ManagedThreadId);
        for (int i = 1; i <= 10; i++)
        {
            Console.Write(i + " ");
        }
    }
    finally
    {
        Monitor.Exit(ThreadLock);
    }
}

Here with a little more code you can see having the try..finally block. Other than Enter() and Exit() methods, the Monitor class also provides the methods like Monitor.Pulse() and PulseAll() to inform the waiting threads that it has completed.

Simple operations using the Interlocked Type

To perform some basic operation it's not necessary that you write the block using the lock or Monitor. The System.Threading namespace provides an interesting class that can help you out.

Now you can replace this

lock (ThreadLock)
{
    intVal++;
}

By

int newVal = Interlocked.Increment(ref intVal);

It returns the new values of the updated variable as well as update the referenced value at the same time.

Similarly,

Add()
Exchange() //for swapping
CompareExchange() // Compare a value and then exchange
Equals()
Decrement()
Read()

Are some basic operations you can perform in a multithreaded environment to make your thread safe using the Interlocked class.

Synchronization using the [Synchronization] attribute

The Synchronization attribute is a member of System.Runtime.Remoting.Contexts namespace. In essence, this class-level attribute effectively locks down all instance member code of the object for thread safety. Additionally you have to derive your class from the ContextBoundObject to keep your object within the contextual boundaries.

Here's the complete code:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("----Synchronnization of Threads-----");
        Console.WriteLine("Main Thread {0}", Thread.CurrentThread.ManagedThreadId);
        Printer p = new Printer();

        Thread[] threads = new Thread[5];

        //Queue 5 threads
        for (int i = 0; i < 5; i++)
        {
            threads[i] = new Thread(new ThreadStart(p.PrintNumbersNonSync));
        }
        foreach (Thread t in threads)
        {
            t.Start();
        }

        Console.ReadLine();
    }
}

[Synchronization]
class Printer : ContextBoundObject
{
    public void PrintNumbersNonSync()
    {
        Console.WriteLine(" ");
        Console.WriteLine("Executing Thread {0}", Thread.CurrentThread.ManagedThreadId);
        for (int i = 1; i <= 10; i++)
        {
            Console.Write(i + " ");
        }
    }
}

Output:

Multithreaded application in .Net

This approach is a lazy way to write thread safe code because CLR that can lock non-threaded sensitive data and that could be a victim of Over Locking. So please choose this approach wisely and carefully.

Happy Threading…!! 

Login to add your contents and source code to this article
share this article :
post comment
 

Helpful article. thanks

Posted by Rohatash Kumar Jul 26, 2011

Useful Article

Posted by Angelina Erin Jul 26, 2011
Team Foundation Server Hosting
Become a Sponsor
PREMIUM SPONSORS
  • ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications.
    Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
Become a Sponsor