Home > Back-end >  Explaining deadlocks with a single lock from The Little Go Book
Explaining deadlocks with a single lock from The Little Go Book

Time:12-20

I'm reading The Little Go Book.

Page 76 demonstrates how you can deadlock with a single lock:

var (
    lock sync.Mutex
)

func main() {
    go func() { lock.Lock() }()
    time.Sleep(time.Millisecond * 10)
    lock.Lock()
}

Running this results in a deadlock as explained by the author. However, what I don't understand is why.

I changed the program to this:

var (
    lock sync.Mutex
)

func main() {
    go func() { lock.Lock() }()
    lock.Lock()
}

My expectation was that a deadlock would still be thrown. But it wasn't.

Could someone explain to me what's happening here please?

The only scenario I can think of that explains this is the following (but this is guesswork):

First example

  1. The lock is acquired in the first goroutine
  2. The call to time.Sleep() ensures the lock is acquired
  3. The main function attempts to acquire the lock resulting in a deadlock
  4. Program exits

Second example

  1. The lock is acquired in the first goroutine but this takes some time to happen (??)
  2. Since there is no delay the main function acquires the lock before the goroutine can
  3. Program exits

CodePudding user response:

In the first example, main sleeps long enough to give the child goroutine the opportunity to start and acquire the lock. That goroutine then will merrily exit without releasing the lock.

By the time main resumes its control flow, the shared mutex is locked so the next attempt to acquire it will block forever. Since at this point main is the only routine left alive, blocking forever results in a deadlock.


In the second example, without the call to time.Sleep, main proceeds straight away to acquire the lock. This succeeds, so main goes ahead and exits. The child goroutine would then block forever, but since main has exited, the program just terminates, without deadlock.

By the way, even if main didn't exit, as long as there is at least one goroutine which is not blocking, there's no deadlock. For this purpose, time.Sleep is not a blocking operation, it simply pauses execution for the specified time duration.

  • Related