golang 死锁就一定会触发all goroutines are asleep - deadlock!吗?

一般其它高级语言,死锁的表现都为程序卡死,但是go则不然,它有可能不卡死有可能卡死,则分情况看

我们来看看死锁的两个情况

  1. 死锁直接panic报all goroutines are asleep - deadlock!
import (
	"fmt"
	"sync"
)

func main() {
	var lock sync.RWMutex
	lock.Lock()
	fmt.Println("this is test examples")
	lock.Lock()
	lock.Unlock()
	lock.Unlock()
}
  1. 死锁直接卡死
package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	var lock sync.RWMutex
	lock.Lock()
	go func() {
	    // time.Sleep也可以看作是一个timer,它的实现见E:\WorkSpace\github\go1.14.6-analysis\src\runtime\time.go函数func timeSleep()
		time.Sleep(10000 * time.Second)
	}()
	fmt.Println("this is test examples")
	lock.Lock()
	lock.Unlock()
	lock.Unlock()
}

源码中见分晓

让我们来看看go sdk的源码,见E:\WorkSpace\github\go1.14.6-analysis\src\runtime\proc.go
中的checkdead函数,这里我们只截取部分代码端,大致调用链为func main() ->func systemstack()->func sysmon()->func checkded()

func checkdead(){
	...
	var run0 int32
	if !iscgo && cgoHasExtraM {
		mp := lockextra(true)
		haveExtraM := extraMCount > 0
		unlockextra(mp)
		if haveExtraM {
			run0 = 1
		}
	}
	// 由上面的逻辑知道run0 只能为1或者0
	// 这里的是获取正在运行的M的数量,它等于总m个数-当前等待工作的空闲 m 计数-当前等待工作的被 lock 的 m 计数-系统m的数量
	run := mcount() - sched.nmidle - sched.nmidlelocked - sched.nmsys
	if run > run0 {
		return
	}
	if run < 0 {
		print("runtime: checkdead: nmidle=", sched.nmidle, " nmidlelocked=", sched.nmidlelocked, " mcount=", mcount(), " nmsys=", sched.nmsys, "\n")
		throw("checkdead: inconsistent counts")
	}
	//如果上面的两个if判断都未命中,则run的个数要么大于1要么大于0
	...
	// There are no goroutines running, so we can look at the P's.
	for _, _p_ := range allp {
		// 这里的allp就是runtime 的 全局 P 队列 (存放所有 P),遍历每个p上的timers的个数,只要有一个p的timer的个数大于0都不会触发all goroutines are asleep - deadlock
		if len(_p_.timers) > 0 {
			return
		}
	}

	getg().m.throwing = -1 // do not dump full stacks
	unlock(&sched.lock)    // unlock so that GODEBUG=scheddetail=1 doesn't hang
	throw("all goroutines are asleep - deadlock!")
}

综上死锁直接panic报all goroutines are asleep - deadlock!的直接原因还是所有全局p队列中的每个p上的timer个数小于等于0了,如果有哪里说的不对,还请各位大佬不吝赐教!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值