CLR Threads Via C# Part 4 – Mutex and lock

In this post I cover the lock keyword in C#, deadlocking, and what a mutex is and how to use it in C#.

Advertisements

In the last post we talked about the various reasons why you would want to synchronize code, and why it’s important to have and use locking mechanisms when working with shared resources. In this post, I want to cover a few more lock types that you will likely find beneficial when writing multi-threaded code, the Mutex and the “lock” keyword.

The lock keyword

In the last post we discussed monitors, which allow synchronization to happen by having an object that represents a key to the monitors encapsulated code, which is then is used by a thread to gain access to that particular critical section of code, the thread then relinquishes ownership of the lock when it’s done. Normally what you’d want to do with monitors is something like the following:

            object o = new object();
            if(Monitor.TryEnter(o))
            {
                try
                {
                    // do some stuff
                }
                catch
                {

                }
                finally
                {
                    Monitor.Exit(o);
                }
            }

In this case, in the event that an exception occurs, the thread will still relinquish ownership of the key object, this is the safest way to use Monitors, but it’s a bit clunky having to write try/catch/finally blocks everywhere. A better option would be having this behavior handled for us, enter the lock keyword.

The lock keyword is essentially the same thing as a monitor (I’ve in fact heard they are the same thing under the hood, but I’m unsure of this), except they wrap all of the exception handling block for us. Let’s look at an example of using a lock:

            object j = new object();

            var count = 0;
            for(int i = 0; i < 10; i++)
            {
                Thread t = new Thread(() => {
                    lock (j)
                    {
                        count++;
                        Console.WriteLine(count);
                    }
                });
                t.Start();
            }

In this code, using lock is equal to having a Monitor.Enter with exception handling and a Monitor.Exit, pretty awesome if you ask me. By the way, all this code does is output the value of count, so 1 – 10, in order, simple as that. That’s all I have to say about locks, moving on.

Deadlocks

I want to talk about what a mutex is and how to use one, but before we can understand the benefits of a mutex, we really need to understand deadlocking. To explain deadlocks, we’ll need to look at an example of a deadlock scenario. Let’s say we have two shared resources, and two threads to keep this simple. Thread 1 wants access to resource one, it requests access to that shared resource, is given a lock, and it proceeds to work with the shared resource. While this is happening we have another shared resource, and thread 2 wants access to it, it requests the key to shared resource 2 and it’s granted, thread 2 proceeds to work with shared resource 2. Our scenario is as follows:

Thread1 ---> Resource 1
Thread2 ---> Resource 2

Now, later on, before thread 1 relinquishes ownership of the key that is locking resource 1, it needs to work with resource 2, except the key is held by thread 2 at the moment, so it goes to sleep. Our scenario is now as follows:

Thread1 ---> Resource 1 -x-> Resource 2 [Thread 1 sleeps waiting on thread 2]
Thread2 ---> Resource 2

Now imagine that thread 2, while thread 1 is sleeping, decides it needs access to resource 1. The problem now is that thread 1 owns the key to resource 1, and it’s asleep waiting on thread 2 to finish up with resource 2, so thread 2 goes into a sleep state as well, our scenario now looks like this:

Thread1 ---> Resource 1 -x-> Resource 2 [Thread 1 asleep waiting on thread 2]
Thread2 ---> Resource 2 -x-> Resource 2 [Thread 2 asleep waiting on thread 1]

What’s happened is both of these threads are waiting on the other thread to finish, and they’ve both gone into a sleep state waiting for each other, this has halted execution of these threads, resulting in a deadlock. Now that we understand the general idea of a deadlock (hopefully) we can see the advantage of a mutex.

Mutex

Mutex is short for “Mutually exclusive”, if you’ve never heard that term before, it means 1 to 1, as in party 1 deals exclusively with the party 2, and party 2 deals exclusively with party 1. In the case of a synchronization primitive, this means that one lock is give to one critical section of code, and one thread may own that lock at any given time. A mutex in C# is an FCL (Framework Class Library) wrapper around the Win32 kernel object version of a mutex. To use a mutex in C#, you simply use an instance of the Mutex class under System.Threading.Mutex. As always, the first thing I like to do when analyzing a new class is to just go look at it’s definition, so let’s do that, the entirety of the mutex class is as follows:

public Mutex();
public Mutex(bool initiallyOwned);
public Mutex(bool initiallyOwned, string name);
public Mutex(bool initiallyOwned, string name, out bool createdNew);
public Mutex(bool initiallyOwned, string name, out bool createdNew, MutexSecurity mutexSecurity);

public static Mutex OpenExisting(string name);
public static Mutex OpenExisting(string name, MutexRights rights);
public static bool TryOpenExisting(string name, out Mutex result);
public static bool TryOpenExisting(string name, MutexRights rights, out Mutex result);
public MutexSecurity GetAccessControl();
public void ReleaseMutex();
public void SetAccessControl(MutexSecurity mutexSecurity);

Alright, so we’ve got an empty constructor that initializes a mutex with default properties. Next, constructor with an “initiallyOwned” parameter, which let’s you specify whether the thread you’ve initialized the mutex with actually owns the mutex, a version with a “name” parameter which let’s you specify a name, another with “createdNew”, which will return whether or not a mutex with the specified name already exists (false if the mutex was unnamed), and finally a version that let’s you specify the mutex security access control to be applied to the particular mutex. Note that the mutex class only has 3 non-static methods, the remaining methods allow you to find an existing mutex by name so you can have an object that represents the instance of that mutex. The 3 methods the mutex class provides to us on an instance level are ReleaseMutex, SetAccessControl, and GetAccessControl. Basically, the two access control methods are exactly what they are named as, getter and setter methods, they simply let you get and set the access control of the mutex if you didn’t specify one in the constructor (or if you did for that matter), and finally ReleaseMutex let’s you release the mutex once. I said this is all the Mutex class itself offers, but the mutex class also inherits from another System.Threading class called “WaitHandle”, which is how we handle synchronization of code with a mutex. We’ll look more at this when we see how to use a mutex.

We’ve broken down the class, but we still have a lingering question, which is why would we want to use this over a monitor or lock? The reason is that a mutex can help address deadlocking by allowing you to specify a timeout period for lock acquisition, so for example if a thread owns the mutex, and another thread tries to get it, if the current thread that owns the mutex takes longer than a specified amount of time to relinquish ownership of the key, let’s say 50 milliseconds, then the requesting thread goes off and does something else rather than getting blocked (well…blocked for longer than the timeout period). Obviously this prevents deadlocking because if a thread can move on if it can’t access the mutex, then we can can avoid the threads permanently blocking. Now just to be clear, using a mutex shouldn’t be something you use to address known deadlocks, ideally a deadlock should be avoided every time no matter what. A mutex should be used as a fail safe, just like releasing a threads key in a finally block; you don’t write a finally block to account for poor code, you write good code where the thread releases a key without throwing an exception, and you write the finally block just to be safe in case you missed something.

One more thing I want to cover on mutexs before I show you how to use them is their negatives. A mutex is a kernel mode object, meaning that every time you acquire and release a mutex, you have to make a round trip to the kernel because user mode can’t touch kernel mode. You also have to cleanup a mutex when it’s not needed anymore, whereas a monitor being static doesn’t need any memory management as far as we’re concerned, this will be handled automatically by the CLR, but it will incur a small hit.

To implement a mutex, let’s look at our previous code, but now implemented via a mutex:

            Mutex m = new Mutex();

            var count = 0;
            for(int i = 0; i < 10; i++)
            {
                Thread t = new Thread(() => {
                    if(m.WaitOne())
                    { 
                        count++;
                        Console.WriteLine(count);
                        m.ReleaseMutex();
                    }
                });
                t.Start();
            }

So literally all we have to do here is instead of lock, we use “WaitOne” inside an if, this method let’s us wait until the mutex has been released, at which time the thread is free to access this critical section. When we finish work in the critical section we call ReleaseMutex, which as I said releases the mutex once. What do I actually mean when I say “releases the mutex once”? Well, let’s modify this code a little bit to where each thread will increment the counter twice instead of once, one increment in one critical section, and another increment in a nested critical section:

            Mutex m = new Mutex();

            var count = 0;
            for(int i = 0; i < 10; i++)
            {
                Thread t = new Thread(() => {
                    if(m.WaitOne())
                    { 
                        count++;
                        Console.WriteLine(count + " from critical section 1");
                        if(m.WaitOne())
                        {
                            count++;
                            Console.WriteLine(count + " from critical section 2");
                            m.ReleaseMutex();
                        }
                        m.ReleaseMutex();
                    }
                });
                t.Start();
            }

In this case, what we should see is the output alternating between critical section 1 and critical section 2 incrementing the counter, and the count should stay in sync, my output is as follows:

1 from critical section 1
2 from critical section 2
3 from critical section 1
4 from critical section 2
5 from critical section 1
6 from critical section 2
7 from critical section 1
8 from critical section 2
9 from critical section 1
10 from critical section 2
11 from critical section 1
12 from critical section 2
13 from critical section 1
14 from critical section 2
15 from critical section 1
16 from critical section 2
17 from critical section 1
18 from critical section 2
19 from critical section 1
20 from critical section 2

So there you have it, it works as expected…so to answer the question of how releasing once and wait one works, basically a thread can sort of “stack” ownership of a mutex, so it can claim ownership of the mutex for not just one critical section of code, but many critical sections. In this case, each thread owns the mutex twice, and therefore must release the mutex twice. Once the mutex has been released twice, the next thread can claim the mutex and repeat the process.

One other feature of the mutex that I’ll cover is the timeout feature. To demonstrate this, I modify the code as follows:

            Mutex m = new Mutex();

            var count = 0;
            for(int i = 0; i < 10; i++)
            {
                Thread t = new Thread(() => {
                    if(m.WaitOne(1))
                    {
                        Thread.Sleep(1);
                        count++;
                        Console.WriteLine(count + " from critical section 1");
                        if(m.WaitOne())
                        {
                            count++;
                            Console.WriteLine(count + " from critical section 2");
                            m.ReleaseMutex();
                        }
                        m.ReleaseMutex();
                    }
                });
                t.Start();
            }

The only thing I changed is that the thread, before executing any code, will sleep for 1 millisecond, and WaitOne will wait up to 1 millisecond before moving on. When I run this program, I get the following:

1 from critical section 1
2 from critical section 2
3 from critical section 1
4 from critical section 2
5 from critical section 1
6 from critical section 2
7 from critical section 1
8 from critical section 2

This makes sense, because each thread will wait for up to 1 millisecond, and each thread that owns the mutex works for at minimum 1 millisecond, but in reality it’s longer than that because it then has to run it’s code, release the mutex, etc. so it’s not really the case that every other thread will timeout while waiting, it’s more likely that a little more than half the threads will timeout in this case, and that’s exactly what happened.

Wrap up

Hopefully this was somewhat insightful as to how lock, deadlocking and mutex work. If it was, let me know by reaching out to me via email or in the comments or by liking this post, if it wasn’t and you have corrections or complaints, you can do the same. Thanks for taking the time to read, and until next time.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Advertisements
Advertisements
%d bloggers like this: