一道关于gorotine的死锁问题

一道关于goroutine死锁

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int)
	go fmt.Println(<-ch)
	ch <- 5
	time.Sleep(2 * time.Second)
}

上述结果我选择输出5,分析如下。go关键字启动一个协程A运行,从无缓冲通道ch中读取数据,阻塞等待chan,协程A睡眠,切换到主协程;主协程往通道发送数据,并唤醒协程A,将协程A列入下次可运行队列,协程主动陷入睡眠;golang调度程序调度到协程A,输出5

实际运行上述输出结果为死锁,修改程序

程序B

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int)
	go func() {
		fmt.Println(<-ch)
	}()
	ch <- 5
	time.Sleep(2 * time.Second)
}

上述结果输出5。和原程序结果不同的原因在于协程启动时需要保存上下文参数,程序B中协程启动入参为空,并引用ch;原程序启动先计算参数,然而计算参数时需要等待结果,当主协程准备往ch发送数据,也请求锁,造成死锁。

程序C

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int)
	go func() {
		fmt.Println(<-ch)
	}()
	time.Sleep(2 * time.Second)
}