views:

124

answers:

4

I was trying to create an example for deadlock. I tried the following code. But instead of creating deadlock, it worked like charm. Help me in understanding why it didn't create a deadlock. What change in this code would create a deadlock?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ReferenceTypes
{
    class DeadLockExample
    {
        static int a;
        static int b;

        public static void Main(string[] args)
        {
            DeadLockExample.a = 20;
            DeadLockExample.b = 30;

            DeadLockExample d = new DeadLockExample();

            Thread tA = new Thread(new ThreadStart(d.MethodA));
            Thread tB = new Thread(new ThreadStart(d.MethodB));

            tA.Start();
            tB.Start();

            Console.ReadLine();
        }

        private void MethodA()
        {
            lock (this)
            {
                Console.WriteLine(a);
                Thread.Sleep(1000);
                Console.WriteLine(b);
            }
        }

        private void MethodB()
        {
            lock (this)
            {
                Console.WriteLine(b);
                Thread.Sleep(1000);
                Console.WriteLine(a);
            }
        }
     }
}
+3  A: 

2 locks, 2 threads.

Thread A takes lock A, sleeps and then tries to take lock B. Thread B takes lock B, sleeps and then tries to take lock A, equals a Deadlock.

[Thread A has to sleep long enough so that thread B takes lock B before thread A attempts to acquire it]

Mitch Wheat
A: 

From Wikipedia -

A deadlock is a situation wherein two or more competing actions are each waiting for the other to finish, and thus neither ever does.

You don't fulfil this requirement with your code above - there's never a point where both thread A and thread B are waiting on each other to complete.

Will A
+11  A: 

As everyone else has said, two locks acquired in different orders, so that each is waiting on the other. I also changed one of the Sleep lengths to ensure a high probability of the deadlock occurring.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ReferenceTypes
{
    class DeadLockExample
    {
        static int a;
        static int b;

        static object lockedObjA = new object();
        static object lockedObjB = new object();

        public static void Main(string[] args)
        {
            DeadLockExample.a = 20;
            DeadLockExample.b = 30;

            DeadLockExample d = new DeadLockExample();

            Thread tA = new Thread(new ThreadStart(d.MethodA));
            Thread tB = new Thread(new ThreadStart(d.MethodB));

            tA.Start();
            tB.Start();

            Console.ReadLine();
        }

        private void MethodA()
        {
            lock (DeadLockExample.lockedObjA)
            {
                Console.WriteLine(a);
                Thread.Sleep(1200);

                lock (DeadLockExample.lockedObjB) {
                    Console.WriteLine(b);
                }
            }
        }

        private void MethodB()
        {
            lock (DeadLockExample.lockedObjB)
            {
                Console.WriteLine(b);
                Thread.Sleep(1000);

                lock (DeadLockExample.lockedObjA) {
                    Console.WriteLine(a);
                }
            }
        }
     }
}
qstarin
Except for the fact that the sleeps don't *guarantee* the deadlock to occur (only synchronization can do that), this is a great answer :)
Merlyn Morgan-Graham
I appreciate the answer. Thank you.
SaravananArumugam
This is the quintessential deadlock example. Most deadlocks in practice look exactly like this, except that the lock acquisitions are typically at least 8 calls apart in the stack trace after being routed through callbacks from timer events on threads you didn't even realize were running.
Dan Bryant
+1  A: 

Here are 3 different ways you can cause a deadlock. This list is not exhaustive.

Call a blocking method from within a lock section.

In this example thread A acquires a lock and then immediately calls a blocking method while at the same time thread B attempts to acquire the same lock, but gets hung because thread A is waiting for thread B to signal the event before it will release the lock.

public class Example
{
  ManualResetEvent m_Event = new ManualResetEvent(false);

  void ThreadA()
  {
    lock (this)
    {
      m_Event.WaitOne();
    }
  }

  void ThreadB()
  {
    lock (this)
    {
      m_Event.Set();
    }
  }
}

Acquire two locks out of order.

No explanation is needed here since this is a well known problem.

public class Example
{
  private object m_LockObjectA = new object();
  private object m_LockObjectB = new Object();

  void ThreadA()
  {
    lock (m_LockObjectA) lock (m_LockObjectB) { }
  }

  void ThreadB()
  {
    lock (m_LockObjectB) lock (m_LockObjectA) { }
  }
}

The lock-free deadlock.

This is one my favorite illustrations of a deadlock because no lock or blocking method is involved. The subtlety of the problem is enough to confound even those who are familiar with threading. The issue here is related to the absence of memory barriers. Thread A waits for thread B to set the signal flag while at the same time thread B waits for thread A to reset it all the while neither thread is seeing the changes the other is making because the compiler, JIT, and hardware are free to optimize the reads and writes of the flag in manner that is non-intuitive.

public class Example
{
  private bool m_Signal = false;

  void ThreadA()
  {
    while (!m_Signal);
    m_Signal = false;
  }

  void ThreadB()
  {
    m_Signal = true;
    while (m_Signal);
  }
}
Brian Gideon