Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Talkative Locker Pattern

4.11/5 (5 votes)
25 Nov 2009CPOL2 min read 20.7K   137  
A design pattern to help debug multi-threaded applications.

Introduction

I’ve been reading many of Martin Fowler’s design patterns (and many other design patterns) lately and have come to appreciate them. What I realize is that a design pattern does not necessarily have to be complex to learn, understand, and apply. The pattern just has to solve a particular problem situation. At the very least, the pattern should help the developer create code that is flexible and easy to modify.

Having said that, I have not seen many widespread patterns that approach the topic of helping developers to debug their multi-threaded programs better. We can all agree that debugging multi-threaded code can easily become a nightmare. Tracking down which threads are currently waiting for a lock, which threads are currently executing, and which threads are about to release a lock can be cumbersome.

Background

I wanted to develop a simple design pattern that could make multi-threading debugging much easier for developers. In this article, I introduce the TalkativeLocker Design Pattern.

Details

The TalkativeLocker Pattern is designed to isolate the locking region of the code from the rest of your code. There is a single point where a lock is entered, acquired, and released. In a way, you are really wrapping the area. By isolating this region, you can write logging and debugging information at each point of the locking and execution stages of any thread that enters.

Here is an extremely simple class that demonstrates the TalkativeLocker Pattern:

C#
public class TalkativeLocker<T>
{
    private readonly static object toLock = new object();

    public T EnterLock(IClient client, Func<T> function)
    {
        T result = default(T);
        Console.WriteLine(client.Name + ":Waiting for lock");

        Monitor.Enter(toLock);

        try
        {
            Console.WriteLine(client.Name + ":AquiredLock");
            result = function();
        }
        catch (Exception ex)
        {
            //
        }
        finally
        {
            Console.WriteLine(client.Name + ":About release lock");
            Monitor.Exit(toLock);
        }
        return result;
    }
}

The class TalkativeLocker contains a private object only used for locking: toLock. Notice that it is static. This means that it will be shared. Only one thread at a time will be able to acquire a lock on it. TalkativeLocker also has a Func<T> parameter. This parameter represents the procedure to call when the lock is acquired. Developers can use any parameter they wish. I chose Func<T> for simplicity.

The IClient interface parameter represents the class that will be using the TalkativeLocker class. Here is the code for the interface:

C#
public interface IClient
{
    string Name
    {
        get;
        set;
    }
}

The interface currently only has one property: Name. The Name property is used by the TalkativeLocker class to display any information that developers may see fit to make their multi-threading behavior easier while debugging. If there is more than one client thread, the Name property should be set to a unique value: one that will identify the thread to the developer. Notice the TalkativeLocker class using the Name property on the IClient interface to write out logging information to the console.

Here is a simple class that implements the interface:

C#
public class Client : IClient
{
    private string name = String.Empty;
    private readonly TalkativeLocker<int> talkativeLocker = 
                     new TalkativeLocker<int>();

    public Client(string name)
    {
        Name = name;
    }

    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }

    public int AddTwoNumbers()
    {
        return 1 + 2;
    }

    public void DoSomething()
    {
        int result = talkativeLocker.EnterLock(this, AddTwoNumbers);
    }
}

And a sample class that demonstrates the TalkativeLocker Design Pattern:

C#
static void Main(string[] args)
{
    Client[] clients = new Client[10];

    clients[0] = new Client("1");
    clients[1] = new Client("2");
    clients[2] = new Client("3");
    clients[3] = new Client("4");
    clients[4] = new Client("5");
    clients[5] = new Client("6");
    clients[6] = new Client("7");
    clients[7] = new Client("8");
    clients[8] = new Client("9");
    clients[9] = new Client("10");

    foreach (Client client in clients)
    {
        Thread t = new Thread(client.DoSomething);
        t.Start();
    }

    Thread.CurrentThread.Join();
    Console.ReadLine();
}

Notice that I’ve initialized each client with its own unique ID.

Your output will be the following:

TalkativeLockPattern

I can now see each the status of each thread as they contend for the lock, acquire it, and ultimately release it.

Please let me know if the TalkativeLocker Design Pattern has made debugging your multi-threaded code easier.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)