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

huangapple go评论82阅读模式
英文:

Why this Go program not enter deadlock status as expected?

问题

我是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()
}

如你所见,这段代码运行良好,并打印了一些内容,然后退出,没有任何死锁错误。据我所知,第一个 go func(){} 协程已经返回并锁定了 mux,然后退出。但是其他两个协程将被阻塞,因为 mux 已经被锁定。

函数 runtime.Gosched() 应该将主协程推入唯一的 FIFO 队列(runtime.GOMAXPROCS(1)),对吗?为什么它可以在已经在队列中的另外两个协程之前执行?

顺便说一下,下面的代码将按预期返回死锁错误:

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()
}

谢谢!

英文:

I am a newbie in Go, i wrote this code and hope it will enter deadlock status, but failed.

var mux sync.Mutex

func main() {
    runtime.GOMAXPROCS(1)
    for i := 0; i &lt; 3; i++ {
	go func() {
		log.Println(&quot;Trying to Lock the Mux&quot;)
		mux.Lock()
		log.Println(&quot;The mux is Locked&quot;)
	}()
  }
  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

As you can see. this code run well and print something and then quit without any deadlock error. For I know, the first go func(){} goroutine has returned and locked the mux then quit. But the other two goroutines will be blocked because the mux has already blocked.

The function runtime.Gosched() should push the main goroutine to the only FIFO queue(runtime.GOMAXPROCS(1)) right? why it can be excute before the left two goroutine that already in the queue?

BTW,this following code will return the deadlock error as expected

var mux sync.Mutex

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

		}()
	}
	wg.Wait()
}

Thanks!

答案1

得分: 2

死锁是一种情况,其中所有的 goroutine 都处于等待状态(等待锁或从通道读取等)。原因很简单,如果它们都在等待,那么就没有剩下的人可以执行任何导致等待的 goroutine 继续执行的操作。在你的情况下,你的主函数,也是一个 goroutine,并不处于等待状态。当主 goroutine 退出时,进程也会退出。

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

队列是一个调度队列。运行时会从队列中选择一个 goroutine,运行一段时间,暂停它,然后选择另一个 goroutine。

英文:

A deadlock is a condition where all the goroutines are in waiting state (waiting for lock or reading from channel etc). The reason is simple, if all of them are waiting then there is no one left that can do something that lead to any of the waiting goroutines to continue. In your case your main function, which is also a goroutine is not in waiting state. When the main goroutine exits the process exits too.

> The function runtime.Gosched() should push the main goroutine to the
> only FIFO queue(runtime.GOMAXPROCS(1)) right? why it can be excute
> before the left two goroutine that already in the queue?

The queue is a schedule queue. The runtime will pick a goroutine from the queue, run it for some time, pause it, pick another goroutine.

答案2

得分: 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()

Lock方法锁定m。如果锁已经被占用,调用该方法的goroutine会阻塞,直到锁可用。

所以第二个和第三个goroutine只是在那里等待。这是一种忙等待的方式。然后主goroutine退出,所以第二个和第三个goroutine也会退出。

英文:

For your code:

var mux sync.Mutex

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

There is no deadlock, for

> func (m *Mutex) Lock()
>
> Lock locks m. If the lock is already in use,
> the calling goroutine blocks until the mutex is available.

So the second and third goroutine just wait there. This is busy waiting. then the main goroutine exit, so the second and third goroutine also exist.

huangapple
  • 本文由 发表于 2017年1月17日 09:25:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/41687657.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定