2

Maybe there is other interpretation of "Dead Lock" but AFAIK :

reference

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 :

Example #1

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.


Another example #2

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 :

  • Are Deadlocks involved here?
Community
  • 1
  • 1
Royi Namir
  • 144,742
  • 138
  • 468
  • 792
  • 1
    The second example is not a deadlock. – SLaks Feb 22 '13 at 20:04
  • There is no deadlock in example 2. Assume two threads each run the doXXX methods and ILockMyself is the same reference. If T1.ILockMyself.doThat takes the lock first, nothing happens because doThat has no mutual ressource which T2.WeveGotAProblem has locked so it runs to completion and releases the lock. If T2.WeveGotAProblem.doThis takes the lock first, there will be a nested lock on the same reference which is released in order,no issue there. – Alex Feb 22 '13 at 20:36
  • @Alex Thank you for the **detailed** reply .this should be posted to David's answer ( or better - as an answer) . cause he claims the opposite..... – Royi Namir Feb 22 '13 at 20:38
  • In #2, the lock 'this' is exposed to the outside world (even if it's internal class, it can still be seen by the rest of the assembly). This is just poor practice in general. You never want to expose you're lock object like that, it should be a private member so that ONLY ILockMySelf can access it. This promotes encapsulation and make it impossible for an external entity to cause the deadlock. – Despertar Feb 22 '13 at 20:50
  • @Despertar I know perfectly well not to expose `this`. however I saw those 2 answers which dont have **each resource wait to another** and both of OP's said that this cause a deadlock. **and please notice. there are 4 people participant in this conversation - and every one of them provide another conclusion :-) BOTH op's says it is a deadlock. slacks says : only the first one , david says none , Brians says the second is a deadlock. and I say. WT** – Royi Namir Feb 22 '13 at 20:52

3 Answers3

3

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.

  • Thread 1 is waiting for thread2 to return.
  • Thread 2 is waiting for thread1 to release a resource that it requires before it can return.

The first example (albeit contrived...why send a thread to sleep forever...?) can result in a deadlock for similar reasons.

E.G.

  • Thread1 waits for Thread.Sleep() to return (it never will)
  • Thread2 waits for Thread1 to release the lock on lockable (it never will)

The fact that the actions are threads and each thread is waiting on a different result is just implementation details.

P.Brian.Mackey
  • 43,228
  • 68
  • 238
  • 348
  • look st my reply to David. I wrote that locks are re-entrent and I dont understand why he claims that #2 is a deadlock. – Royi Namir Feb 22 '13 at 20:42
  • P.s. the second example OP does say **Following line should run in a separate thread for the deadlock to happen** – Royi Namir Feb 22 '13 at 20:42
  • @Royi Namir - #2 is *not* a deadlock. Per your new comment, yes it would become a deadlock. But, as it stands no it is technically not a deadlock. – P.Brian.Mackey Feb 22 '13 at 20:42
  • so just to be sure ( sorry) : if the line `anObjectIShouldntUseToLock.doThat();` would have run in **another** thread - it become a deadlock . right ? – Royi Namir Feb 22 '13 at 20:45
  • @RoyiNamir - Yes. If you run it that way (the way I posted in this answer) it deadlocks. – P.Brian.Mackey Feb 22 '13 at 20:46
  • Ok so you think like the original OP. So I'll ask again. even if they both run in separate threads , **only one** side is waiting to another. **not** both sides.which is not what is written at http://tinyurl.com/azkg9f3) – Royi Namir Feb 22 '13 at 20:47
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/24986/discussion-between-royi-namir-and-p-brian-mackey) – Royi Namir Feb 22 '13 at 21:07
2

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.

Community
  • 1
  • 1
Brian Gideon
  • 47,849
  • 13
  • 107
  • 150
1

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

David Hope
  • 2,216
  • 16
  • 32
  • if it was on the same thread, there was no prob cause I can re-entrant lock. the whole idea is lock on another thread. – Royi Namir Feb 22 '13 at 20:12
  • 1
    which idea? deadlock doesn't imply multiple threads. You are the one who assigned that property. – David Hope Feb 22 '13 at 20:15
  • Looking at the second example , assuming it runs as it suppose to ( doThat() on another thread) , where is the _"waiting for the other to finish"_ part here ? `lock(anObjectIShouldntUseToLock){..}` is locking the reference , but it doesn't wait to anyone- which is what the definition states. can you please explain ? in order to have a dead lock _ competing actions are each waiting for the other to finish !_ there is only one part who is waiting for the other to end. – Royi Namir Feb 22 '13 at 20:24
  • 1
    sorry, neglected the re-entrancy of lock, so, then, `technically` neither are deadlocks – David Hope Feb 22 '13 at 20:44