Golang死锁vs操作系统死锁

目录

一、死锁

二、Golang死锁场景

[2.1 重复上锁](#2.1 重复上锁)

[2.2 不会减少的 WaitGroup](#2.2 不会减少的 WaitGroup)

[2.3 空select](#2.3 空select)

[2.4 channel](#2.4 channel)


一、死锁

1.golang中死锁的触发条件:

死锁是当 Goroutine 被阻塞而无法解除阻塞时产生的一种状态。

2.操作系统死锁:

发生死锁时,线程永远不能完成,系统资源被阻碍使用,以致于阻止了其他作业开始执行。在讨论处理死锁问题的各种方法之前,我们首先深入讨论一下死锁特点。

必要条件:

如果在一个系统中以下四个条件同时成立,那么就能引起死锁:

  • 互斥:至少有一个资源必须处于非共享模式,即一次只有一个线程可使用。如果另一线程申请该资源,那么申请线程应等到该资源释放为止。
  • 占有并等待:---个线程应占有至少一个资源,并等待另一个资源,而该资源为其他线程所占有。
  • 非抢占:资源不能被抢占,即资源只能被线程在完成任务后自愿释放。
  • 循环等待:有一组等待线程 {P0,P1,...,Pn},P0 等待的资源为 P1 占有,P1 等待的资源为 P2 占有,......,Pn-1 等待的资源为 Pn 占有,Pn 等待的资源为 P0 占有。

我们强调所有四个条件必须同时成立才会出现死锁。循环等待条件意味着占有并等待条件,这样四个条件并不完全独立。

二、Golang死锁场景

2.1 重复上锁

写写冲突,读写冲突,读读不冲突。golang中的锁是不可重入锁,对已经上了锁的写锁,再次申请锁是会报死锁。上了读锁的锁,再次申请写锁会报死锁,而申请读锁不会报错。

案例1:

重复上写锁

Go 复制代码
package main
import(
	"sync"
)
func main(){
	var lock sync.Mutex
	lock.Lock()
	lock.Lock()
}

结果:死锁

正常情况:

Go 复制代码
func main() {
	var lock sync.RWMutex
	lock.RLock()
	lock.RLock()
}
//正常执行

2.2 不会减少的 WaitGroup

不会减少的 WaitGroup会永久阻塞

案例1:

Go 复制代码
func main() {
	var wg sync.WaitGroup
	wg.Add(1)
	wg.Wait()
  //报死锁错误
}

结果:

2.3 空select

案例:

Go 复制代码
package main

func main() {
	select {
	
	}
}
//报死锁错误

结果:

2.4 channel

1.为 nil 的channel 发送、接受数据都会阻塞;

2.无缓冲的channel 发送、接受数据都会阻塞。解决方案:边接受边读取

3.channel 缓冲区满了的,继续发送数据会阻塞。解决办法:读取channel中的数据

4.当 ch 中没有数据的时候,就是从空的channel中接受数据,for range ch 会发生阻塞,但是无法解除阻塞,发生死锁。 解决:当数据发送完了过后,close channel

案例1:

Go 复制代码
func main() {
	var ch chan struct{}
	ch <- struct{}{}
}
//报死锁错误

结果:

案例2:

Go 复制代码
func main() {
	ch := make(chan struct{})
	<- ch
}
//报死锁错误

结果:

参考:关于golang中死锁的思考与学习_Golang_脚本之家

相关推荐
Java开发追求者8 小时前
Go环境开发配置
go·go环境开发配置·环境开发配置
程序员爱钓鱼14 小时前
配置 GoLand 与 VS Code 开发环境
前端·后端·go
fcu3dx2 天前
Go + PostgreSQL 餐饮SaaS后端架构:从单体到多租户的实战重构
go
程序员爱钓鱼2 天前
Go 开发环境安装(Windows、macOS、Linux)
后端·面试·go
ArixBit3 天前
用 Go 手撸 Agent 框架 #11:工具从哪里来——内置工具、MCP 与 Skills
go·agent
程序员爱钓鱼3 天前
为什么学习 Go?Go 能做什么?
后端·面试·go
用户095367515833 天前
在系统的学习 redis 前的疑惑
redis·go
名字还没想好☜3 天前
Go 用 errgroup 管理并发子任务:错误收敛、取消传播与限流
开发语言·后端·golang·go·并发
labixiong4 天前
TypeScript 7.0 编译器用 Go 重写,速度暴增10倍——背后到底做了什么?
前端·javascript·go
名字还没想好☜4 天前
Go 的 time.Ticker 陷阱:定时任务里被忽略的内存泄漏与正确关闭
java·数据库·golang·go·定时器