为什么这个Go程序没有按预期进入死锁状态?

时间:2017-01-17 01:25:16

标签: go concurrency

我是Go的新手,我写了这段代码并希望它会进入死锁状态,但失败了。

var mux sync.Mutex

func main() {
    runtime.GOMAXPROCS(1)
    for i := 0; i < 3; i++ {
    go func() {
        log.Println("Trying to Lock the Mux")
        mux.Lock()
        log.Println("The mux is Locked")
    }()
  }
  runtime.Gosched()
}
//Output:
//2017/01/17 08:59:42 Trying to Lock the Mux
//2017/01/17 08:59:42 The mux is Locked
//2017/01/17 08:59:42 Trying to Lock the Mux
//2017/01/17 08:59:42 Trying to Lock the Mux

如你所见。这段代码运行良好并打印一些东西然后退出而没有任何死锁错误。我知道,第一个去func(){} goroutine已经返回并锁定了多路复用器然后退出。但其他两个goroutines将被阻止,因为多路复用器已经被阻止。

函数 runtime.Gosched()应该将主goroutine推送到唯一的FIFO队列( runtime.GOMAXPROCS(1))吗?为什么它可以在已经在队列中的左两个goroutine之前执行?

顺便说一句,以下代码将按预期返回死锁错误

var mux sync.Mutex

func main() {
    runtime.GOMAXPROCS(1)
    var wg sync.WaitGroup
    wg.Add(3)
    for i := 0; i < 3; i++ {
        go func() {
            defer wg.Done()
            log.Println("Trying to Lock the Mux")
            mux.Lock()
            log.Println("The mux is Locked")

        }()
    }
    wg.Wait()
}

谢谢!

2 个答案:

答案 0 :(得分:2)

死锁是一种情况,其中所有 goroutines处于等待状态(等待锁定或从通道读取等)。原因很简单,如果他们所有人都在等待那么就没有人可以做任何导致任何等待的goroutine继续下去的事情。在您的情况下,您的主要功能,也是一个goroutine不处于等待状态。当主要的goroutine退出进程时也会退出。

  

函数runtime.Gosched()应该将主goroutine推送到   只有FIFO队列(runtime.GOMAXPROCS(1))对吗?为什么它可以执行   在已经在队列中的左两个goroutine之前?

队列是一个计划队列。运行时将从队列中选择一个goroutine,运行一段时间,暂停它,选择另一个goroutine。

答案 1 :(得分:1)

代码:

var mux sync.Mutex

func main() {
    runtime.GOMAXPROCS(1)
    for i := 0; i < 3; i++ {
    go func() {
        log.Println("Trying to Lock the Mux")
        mux.Lock()
        log.Println("The mux is Locked")
    }()
  }
  runtime.Gosched()
}

没有死锁
  

func(m * Mutex)Lock()

     

锁定锁。如果锁已被使用,   调用goroutine阻塞,直到互斥锁可用。

所以第二和第三个goroutine就在那里等待。这是busy waiting。然后是主要的goroutine出口,所以第二和第三个goroutine也存在。

相关问题