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);
}
}
}
}
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);
}
}
}
}
}
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]
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With