Reputation: 148514
Maybe there is other interpretation of "Dead Lock" but AFAIK :
A deadlock happens when two threads each wait for a resource held by the other, so neither can proceed.
But I've seen couple of answers here on SO which claims that a long wait ( without waiting for each other) is also a deadlock :
namespace ConsoleApplication7
{
public class Program
{
public static void Main(string[] args)
{
LockableClass lockable = new LockableClass();
new Thread(new ParameterizedThreadStart(BackgroundMethod)).Start(lockable);
Thread.Sleep(500);
Console.Out.WriteLine("calling Reset");
lockable.Reset();
}
private static void BackgroundMethod(Object lockable)
{
lock (lockable)
{
Console.Out.WriteLine("background thread got lock now");
Thread.Sleep(Timeout.Infinite);
}
}
}
public class LockableClass
{
public Int32 Value1 { get; set; }
public Int32 Value2 { get; set; }
public void Reset()
{
Console.Out.WriteLine("attempting to lock on object");
lock (this)
{
Console.Out.WriteLine("main thread got lock now");
Value1 = 0;
Value2 = 0;
}
}
}
}
Pardon me but all I see here is a pure lock that hasn't been released. it is not a situation both threads waiting for another. The Thread here does NOT wait for the main thread to finish.
class ILockMySelf
{
void doThat()
{
lock(this){ ... }
}
}
class WeveGotAProblem
{
ILockMySelf anObjectIShouldntUseToLock;
void doThis()
{
lock(anObjectIShouldntUseToLock)
{
// Following line should run in a separate thread
// for the deadlock to happen
anObjectIShouldntUseToLock.doThat();
}
}
}
Same here. the thread which runs doThis
is NOT waiting for the "separate thread" which will run doThat
Question :
Upvotes: 2
Views: 295
Reputation: 48949
Regarding Example 1:
I personally do not consider this a deadlock but that is only because of the semantic meaning I place on the word "deadlock". Sure, in this example neither thread will proceed so it has the same affect as a deadlock, but it is not because each thread is waiting for a resource held by the other. Instead the thread executing BackgroundMethod
(call it T1) is just waiting...and waiting...for nothing. There is no action the thread executing Reset
(call it T2) can take to unblock T11 because T2 is not waiting for a resource held by T1. It is for this reason that I do not consider this a deadlock. But, I am not going to gripe too much if someone else disagrees with me on that.
Regarding Example 2:
As others have pointed out this is not a deadlock either. Except this time it is because neither thread will block. One reason is because a lock
is re-entrant. But, even if you did get doThat
running on another thread the code still would not deadlock because doThis
immediately releases the lock. I think P.Brian.Mackey covers this pretty well in his answer already so there is no reason for me to expound further.
Now for the fun stuff
The following is one of my favorite illustrations of a deadlock because no lock or blocking method is involved. The subtlety of the problem is mind numbing. 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 a manner that is non-intuitive.
In this example the simple bool
variable signal
is the resource. Or, more abstractly, it is the memory that is a resource. Because of the way software and hardware optimizations are applied memory operations can have acquire-release semantics. That's the whole point behind memory barriers. In fact, the formal definitions for memory fences (or barriers) use the terms acquire and release because memory is a resource that can be manipulated just like any other resource.
Disclaimer: Reproducibility may vary depending on your environment and build configuration.
public class Example
{
private bool signal = false;
void ThreadA()
{
while (!signal);
signal = false;
}
void ThreadB()
{
signal = true;
while (signal);
}
}
1To be completely pedantic you could call Thread.Interrupt
to "poke" the Thread.Sleep
call.
Upvotes: 2
Reputation: 44275
I agree with David Hope in that the definition of a Deadlock is broad and applies to scenarios outside of threading. However, the second example is not a Deadlock because it doesn't have circumstances that cause the threads to "halt".
To correct the second example, spin up the a new thread and force thread1 to wait on thread2. Then, you can create a deadlock:
//Deadlock
public class Program
{
public static void Main(string[] args)
{
WeveGotAProblem p = new WeveGotAProblem();
p.doThis();//gain a lock on this thread
}
}
class ILockMySelf
{
public void doThat()
{
//Thread2 waits on Thread1 to release "this"
lock (this)
{
Console.WriteLine("that");
}
}
}
class WeveGotAProblem
{
ILockMySelf anObjectIShouldntUseToLock = new ILockMySelf();
public void doThis()
{
lock (anObjectIShouldntUseToLock)
{
Task task = Task.Factory.StartNew(new Action(() => anObjectIShouldntUseToLock.doThat()));
Task.WaitAll(task);//Thread1 waits on Thread2 to return. This is important
}
}
}
Here we have two or more competing actions each waiting for the other to finish.
The first example (albeit contrived...why send a thread to sleep forever...?) can result in a deadlock for similar reasons.
E.G.
The fact that the actions are threads and each thread is waiting on a different result is just implementation details.
Upvotes: 3
Reputation: 2256
Really, it depends on your definition of deadlock
, hence the problem...
According to wikipedia, deadlock is:
A deadlock is a situation in which two or more competing actions are each waiting for the other to finish, and thus neither ever does.
You infer from either definition that activities or actions must be in different threads, which is not what the definition says.
So, I would technically conclude that example 1 is NOT a deadlock, because the background thread is never going to end (outside of an exception) regardless, but Example #2 is a deadlock, because if the two actions were not competing for the same resource, then execute flow would be fine.
In both cases, there is a programming error (#2 is more of an error, where #1 looks like a contrived example), which is causing the code to fail to make forward progress.
So, in either case...there is a problem to fix, regardless of the specific intent or usage of the word deadlock
Upvotes: 1