Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Master Managed Threading and Synchronization Techniques : Page 3

Dive deep into the various synchronization techniques available in the .NET framework, including inter-thread and inter-process synchronization.


advertisement
Synchronization Techniques
Thread synchronization is the biggest challenge developers face when developing multi-threaded applications. COM components use apartments to synchronize access to resources. While managed development uses different techniques, such as locking, signaling, and so on, to ensure thread-safe execution, for compatibility with the older COM model, the framework initializes all managed threads in the multi-threaded apartment (MTA) unless the thread's apartment state has been set prior to starting the thread. You can find all the code examples in this article in the downloadable sample code.

The following code invokes multiple threads, which in turn execute a method on an object. The method simply prints the ID of the executing thread. There are no synchronization issues, because the threads work on different objects.

namespace ThreadingInDotNet { class Program { static void Main(string[] args) { ThreadSafeType tst1 = new ThreadSafeType(); ThreadSafeType tst2 = new ThreadSafeType(); Thread t1 = new Thread(new ThreadStart( tst1.PrintThreadId)); Thread t2 = new Thread(new ThreadStart( tst2.PrintThreadId)); t1.Start(); t2.Start(); } } class ThreadSafeType { int counter = 0; public void PrintThreadId() { for (int i = 0; i < 5; i++) { counter++; Console.WriteLine("Thread id : " + Thread.CurrentThread.GetHashCode() + " added one to counter. Counter Value : " + counter); Thread.Sleep(1000); } Console.WriteLine(counter); } } }

In contrast, consider the following code, where two threads both work on the same object:

namespace ThreadingInDotNet { class Program { static void Main(string[] args) { ThreadSafeType tst = new ThreadSafeType(); Thread t1 = new Thread(new ThreadStart( tst.PrintThreadId)); Thread t2 = new Thread(new ThreadStart( tst.PrintThreadId)); t1.Start(); t2.Start(); } } class ThreadSafeType { int counter = 0; public void PrintThreadId() { for (int i = 0; i < 5; i++) { counter++; Console.WriteLine("Thread id : " + Thread.CurrentThread.GetHashCode() + " added one to counter. Counter Value : " + counter); Thread.Sleep(1000); } Console.WriteLine(counter); } } }

The preceding code has two threads working on the same object instance, so results can be unpredictable, and errors can occur randomly. In this case, both threads execute the PrintThreadID method at the same time. Sometimes, both threads will update the value of the counter within a very small interval, so by the time either thread can print the counter value, it has already increased by two, as shown in the output below. You can see that the counter value printed moves from 6 directly to 8, and again from 8 to 10.



Thread id : 3 added one to counter. Counter Value : 1 Thread id : 4 added one to counter. Counter Value : 2 Thread id : 4 added one to counter. Counter Value : 3 Thread id : 3 added one to counter. Counter Value : 4 Thread id : 3 added one to counter. Counter Value : 5 Thread id : 4 added one to counter. Counter Value : 6 Thread id : 4 added one to counter. Counter Value : 8 Thread id : 3 added one to counter. Counter Value : 8 Thread id : 4 added one to counter. Counter Value : 10 Thread id : 3 added one to counter. Counter Value : 10

The .NET Framework provides various techniques for synchronizing access to shared resources. Some work on an "always exclusive" lock basis, while others allow exclusive locking only for writing. Some can provide thread synchronization for only a single process, while others provide system-level synchronization.

Here's a list of the various synchronization techniques discussed in this article:

  • Lock/Monitor
  • Mutexes
  • Interlocked Operations
  • Read-Writer Locks
  • Semaphores
  • Signaling using EventWaitHandle
Synchronization with Lock/Monitor
Locking is a managed synchronization technique where you can synchronize access to a region of code by taking and releasing a lock on a particular object. The points to remember are:

  • Lock implements Monitor to make sure that there are no orphan locks.
  • The Lock technique cannot be serialized across application domains.
  • A Lock has thread affinity.
The following code illustrates synchronization using locks:

class ThreadSafeType { int counter = 0; private Object thisLock = new Object(); public void PrintThreadId() { lock (thisLock) { for (int i = 0; i < 5; i++) { counter++; Console.WriteLine("Thread id : " + Thread.CurrentThread.GetHashCode() + " added one to counter. Counter Value : " + counter); Thread.Sleep(1000); } } Console.WriteLine(counter); } }

The preceding code makes the ThreadSafeType class results more deterministic by introducing a lock in the method. Now, whichever thread gets the lock first will be able to increment the counter five times at one go.

The output from the preceding code looks like this:

Thread id : 3 added one to counter. Counter Value : 1 Thread id : 3 added one to counter. Counter Value : 2 Thread id : 3 added one to counter. Counter Value : 3 Thread id : 3 added one to counter. Counter Value : 4 Thread id : 3 added one to counter. Counter Value : 5 5 Thread id : 4 added one to counter. Counter Value : 6 Thread id : 4 added one to counter. Counter Value : 7 Thread id : 4 added one to counter. Counter Value : 8 Thread id : 4 added one to counter. Counter Value : 9 Thread id : 4 added one to counter. Counter Value : 10 10



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap