Blog Archives

lock and deadlocks (basics)

The main problem of multithreading is sharing data. You cannot access the same data from two different threads at the same time unless they are both reading. Use the lock() command to deal with sharing issues. It is nearly straightforward, just make sure you don’t cause deadlocks.

static void DeadLock() {
    object A = new object();
    object B = new object();

    Task.Factory.StartNew(() => {
        lock (A) {
            Thread.Sleep(1000);
            lock (B) Console.WriteLine("locked A, then B");
        }
    });

    Task.Factory.StartNew(() => {
        lock (B) {
            lock (A) Console.WriteLine("locked B, then A");
        }
    });

    Console.ReadLine();
} //

The example shows a simplified deadlock situation. Two tasks (=threads) wait for access to resources, in this case the objects A and B. The first task blocks access to object A. In the meantime the second task blocks access to object B and then asks for access to A. But A is blocked. The next step is that the first task finishes sleeping and asks for access to B. But B was already blocked by the second task. This results in a classical deadlock situation.

The example uses tasks, you can expect each task to use another thread. But this does not have to be the case.  Don’t expect to be lucky, it won’t work in the long run. It is necessary to assume that each task equals a new thread.
A lock() on an object can be re-entered multiple times by the same thread.

To avoid deadlocks you have to make sure that locks are requested in the same order. And you should only use locks on private objects and avoid “this” as the locking object.

static void Lock() {
    object o = new object();
    bool locked = false;

    try {
        Monitor.Enter(o, ref locked);

        Console.WriteLine("bla bla bla");
        Thread.Sleep(1000); // do something
    }
    finally {
        if (locked) Monitor.Exit(o);
    }

    // equals

    lock (o) {
      Console.WriteLine("bla bla bla");
      Thread.Sleep(1000); // do something
    }

    Console.ReadLine();
} //

The lock command is a shortcut replacing the above code. It uses the Monitor class. Generally there is no reason to not use lock() even though the Monitor class offers a lot of extras.

Advertisements