Download as pdf or txt
Download as pdf or txt
You are on page 1of 4

Monitoring and Mutex

The Monitor is not stack-proof You might expect this program to freeze: //:c16:RecursiveNotLocked.cs using System; using System.Threading; class RecursiveNotLocked { int MAX_CALLS = 4; void RecursiveCall(int callCount){ Console.WriteLine("Entering recursive call"); lock(this){ Console.WriteLine( "Exclusive access to this"); if (callCount < MAX_CALLS) { RecursiveCall(++callCount); } } } public static void Main(){ RecursiveNotLocked rl = new RecursiveNotLocked(); rl.RecursiveCall(0); } }///:~

The first time RecursiveCall( ) is called, it acquires the Monitor to this. Then, from within that locked block, it calls RecursiveCall( ). What happens when it comes to the lock block on this second call? You might think Well, its a different call to the method, so it will block. But the right to enter the block is owned by the calling Thread; since it owns the lock on this, it continues into the lock block and recurses MAX_CALLS times.

Where to monitor An objects thread-safety is entirely a function of the objects state. A class without any static or instance variables, consisting solely of methods that dont call methods that put it into ThreadState.WaitSleepJoin, is inherently thread-safe. Any variables or resources that affect whether your object is in a consistent state should be private or protected and only available to outside objects by way of properties or methods. Its just foolish to ever allow direct references to these critical resources from external objects. If instead you create properties and methods which consistently use the Monitor class (or the equivalent lock blocks), youll save yourself considerable headaches when it comes to locating and debugging threading problems.

Cross-process synchronization with Mutex The Mutex class is similar to the Monitor class, but is used to synchronize behaviour across application domains. And instead of locking on an arbitrary object, the Mutex locks itself owning the Mutex provides cross-process mutual exclusion. You attempt to acquire the Mutex by calling one of the overloaded Mutex.WaitOne( ) methods. If you pass in no arguments, the calling thread goes into ThreadState.WaitSleepJoin until the Mutex is available. Or you can call Mutex.WaitOne( ) with a timeout value and a bool that interacts with the Synchronized Attribute. If you do not use the [Synchronized ( )] attribute, the value you use for this is irrelevant. This example allows only one copy of the application to run on the machine at a time. To run this, open two console windows and run the program in both simultaneously. //Demonstrates "Application Singleton" using System; using System.Threading; class MutexDemo { public static void Main(){ Mutex mutex = new Mutex(false, "MutexDemo"); bool gotTheMutex = mutex.WaitOne(0, true); while (gotTheMutex == false) { Console.WriteLine( "Another app has the Mutex"); Chapter 16: Multithreaded Programming 753 gotTheMutex = mutex.WaitOne(3000, true); } Console.WriteLine( "This application has the mutex"); Thread.Sleep(10000); Console.WriteLine("Okay, I'm done"); } }///:~ When run, th e output of the second instance of the application will be: Another app has the Mutex Another app has the Mutex This application has the mutex (You may have one more or fewer Another app has the Mutex lines, depending on how fast you started the second application.) The first line of MutexDemo.Main( ) instantiates a .NET Mutex that corresponds to an OS-level mutex that is identified at the OS-level by the string MutexDemo. The call to WaitOne(0, true ) returns true immediately the first time the application is called the OS-level MutexDemo mutex is available. Since gotTheMutex is true, the first application reports that it has the mutex and blocks for ten seconds.

If one or more additional applications are run within that ten second period, their calls to WaitOne(0, true ) will immediately return false because the MutexDemo mutex is held by the first application. As long as gotTheMutex is false, the application reports it to the console and calls WaitOne( ), again, this time specifying a 3,000 millisecond timeout. For the purposes of this book, the only thing that you can use a Mutex for is as the basis of cross-process blocking. If your work involves .NET Remoting, youll learn how methods and objects can be invoked and moved across process boundaries and the Mutex will become the basis of synchronizing such behaviours.

You might also like