Introduction
A deadlock is a situation where an application
locks up because two or more activities are waiting for each other to finish.
This occurs in multithreading software where a shared resource is locked by one
thread and another thread is waiting to access it and something occurs so that
the thread holding the locked item is waiting for the other thread to execute.
First, it's important to understand what a
deadlock among threads is and the conditions that lead to one. Many OS course
textbooks will cite the four conditions necessary for a deadlock to occur:
- A limited number of a particular resource.
In the case of a monitor in C# (what you use when you employ the lock
keyword), this limited number is one, since a monitor is a mutual-exclusion
lock (meaning only one thread can own a monitor at a time).
- The ability to hold one resource and
request another. In C#, this is akin to locking on one object and then
locking on another before releasing the first lock, for example:
lock(a)
{
lock(b)
{
....
}
}
- No preemption capability. In C#, this
means that one thread can't force another thread to release a lock.
- A circular wait condition. This means that
there is a cycle of threads, each of which is waiting for the next to
release a resource before it can continue.
If any one of these conditions is not met,
deadlock is not possible. We can avoid all four condition by the followings:
- The first condition is inherent to what a
monitor is, so if you're using monitors, this one is set in stone.
- The second condition could be avoided by
ensuring that you only ever lock one object at a time, but that's frequently
not a feasible requirement in a large software project.
- The third condition could possibly be
avoided in the Microsoft® .NET Framework by
aborting or interrupting the thread holding the resource your thread
requires, but a) that would require knowing which thread owned the resource,
and b) that's an inherently dangerous operation .
To further illustrate how a deadlock might
occur, imagine the following sequence of events:
- Thread 1 acquires lock A.
- Thread 2 acquires lock B.
- Thread 1 attempts to acquire lock B, but
it is already held by Thread 2 and thus Thread 1 blocks until B is released.
- Thread 2 attempts to acquire lock A, but
it is held by Thread 1 and thus Thread 2 blocks until A is released.
At this point, both threads are blocked and
will never wake up. The following C# code demonstrates this situation.
object
lockA = new object();
object lockB = new
object();
Thread 1
void t1()
{
lock (lockA)
{
lock (lockB)
{
/* ... */
}
}
}
Thread 2
void t2()
{
lock (lockB)
{
lock (lockA)
{
/* ... */
}
}
}
We have another code which
demonstrate the deadlock condition as:
using
System;
using
System.Threading;
namespace
deadlockincsharp
{
public class
Akshay
{
static
readonly object firstLock =
new object();
static
readonly object secondLock =
new object();
static void
ThreadJob()
{
Console.WriteLine("\t\t\t\tLocking
firstLock");
lock (firstLock)
{
Console.WriteLine("\t\t\t\tLocked
firstLock");
// Wait until we're fairly sure the
first thread
// has grabbed secondLock
Thread.Sleep(1000);
Console.WriteLine("\t\t\t\tLocking
secondLock");
lock (secondLock)
{
Console.WriteLine("\t\t\t\tLocked
secondLock");
}
Console.WriteLine("\t\t\t\tReleased
secondLock");
}
Console.WriteLine("\t\t\t\tReleased
firstLock");
}
static void
Main()
{
new
Thread(new
ThreadStart(ThreadJob)).Start();
// Wait until we're fairly sure the other
thread
// has grabbed firstLock
Thread.Sleep(500);
Console.WriteLine("Locking
secondLock");
lock (secondLock)
{
Console.WriteLine("Locked
secondLock");
Console.WriteLine("Locking
firstLock");
lock (firstLock)
{
Console.WriteLine("Locked
firstLock");
}
Console.WriteLine("Released
firstLock");
}
Console.WriteLine("Released
secondLock");
Console.Read();
}
}
}
Output
(You'll need to hit Ctrl-C or something similar to
kill the program.) As you can see, each thread grabs one lock and then tries to
grab the other. The calls to
Thread.Sleep
have been
engineered so that they will try to do so at inopportune times, and deadlock.