all goroutines are asleep - deadlock-Go中协程死锁详解

最近学go的channel的时候老是遇到题目中的错误:
fatal error: all goroutines are asleep - deadlock!
对问题研究总结后,在此记录一下

下贴上错误代码:

func testDeadLock(c chan int){
	for{
		fmt.Println(<-c)
	}
}

func main() {
	c :=make(chan int)
	c<-'A'
	go testDeadLock(c)
	time.Sleep(time.Millisecond)
}

看上面main函数中,先开了一个通道channel c,然后马上对这个c内写入数据。
然后调协程testDeadLock在c中取数据,结果运行时报错:
fatal error: all goroutines are asleep - deadlock!

这究竟是咋回事呢?
首先我们这里通过make(chan int),开辟的通道是一种无缓冲通道,所以当对这个缓冲通道写的时候,会一直阻塞等到某个协程对这个缓冲通道读(大家发现没有这个与典型的生产者消费者有点不一样,当队列中“内容”已经满了,生产者再生往里放东西才会阻塞,而这里我讲c<-'A’理解为生产,他却是需要等到某个协程读了再能继续运行)。
main函数的执行在go语言中本身就是一个协程的执行,所以在执行到c<-'A’的时候,执行main函数的协程将被阻塞,换句话说main函数被阻塞了,此时不能在继续往下执行了,所以go testDeadLock©这个函数无法执行到了,就无法读到c中的内容了,所以整个程序阻塞,发生了死锁。

如何解决这个问题呢?大家想一下,我们阻塞的原因是main函数不能继续向下执行了,所以go testDeadLock©执行不到,对吧,那我们在main函数中另开一个协程,让他对c进行写(对c进行写的过程不在main函数对应的协程中做),修改后的代码:

func test(c chan int){
	c<-'A'
}

func testDeadLock(c chan int){
	for{
		fmt.Println(<-c)
	}
}

func main() {
	//chanDemo()
	c :=make(chan int)
	go test(c)
	go testDeadLock(c)
	time.Sleep(time.Millisecond)

}

新增了test函数,在main函数中为test函数开了协程专门执行,让对c的写在test中进行,这样main函数就能继续往下执行,去开一个协程执行testDeadLock函数了,这样一来,虽然刚刚开的test函数中会因为对c的写入发生阻塞但并不会影响main函数对应协程的继续执行,所以之后的testDeadLock马上将从c中读出test函数刚刚写入的内容,这样一来 test中对c写入的内容就被testDeadLock顺利读出并打印了。

你可能感兴趣的:(Go)