Go语言之死锁的4种常见情况

什么是死锁?

 死锁并不是锁的一种,而是一种错误使用锁导致的现象,死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。系统发生死锁现象不仅浪费大量的系统资源,甚至导致整个系统崩溃,带来灾难性后果。所以,对于死锁问题在理论上和技术上都必须予以高度重视。

造成死锁的常见情况

  1. 单go程自己死锁
	func main()  {
		ch:=make(chan int) //声明
		//向ch中写入数据,ch此时等待读出数据,造成堵塞,使得下方读出数据部分的代码不执行,造成死锁
		ch <- 89	
		num:=<- ch
		fmt.Println(num)
	}

2.go程间channel访问顺序导致死锁

	func main()  {
		ch:=make(chan int)
		//进行数据的读取,但是无数据读取,使得阻塞,导致下面go程中的代码不执行造成死锁
		num:= <- ch
		fmt.Println(num)
		//在go程向ch写入数据
		go func() {
			ch <- 89
		}()
	}

3.多go程,多channel 交叉死锁

	func main()  {
		ch1:=make(chan int)
		ch2:=make(chan int)
		//此时主go程和子go程,互相掌握着各自的条件,但都无法释放,造成死锁
		go func() {
			for  {
				select {
					case num:=<-ch1:
						ch2 <- num
				}
			}
		}()
	
		for  {
			select {
				case num := <-ch2:
					ch1<-num
			}
		}
	
	}
  1. 将 互斥锁、读写锁 与 channel 混用。 —— 隐性死锁。
     下面代码造成隐形死锁的原因是,进行readGo函数时,以读的模式加锁,同时 channel 等待数据写入,以便于数据的读出,此时channel等到数据写入造成堵塞,下面代码无法执行,造成以读模式的锁无法解锁。但进入到writeGo函数中时,向下执行时,遇到以写模式加锁时会造成堵塞,因为上方以读的模式的锁并没有解锁,造成以写模式加锁下方的代码无法执行,无法向channel中写入数据,使其互相堵塞,但是控制台并不报错,该死锁称为隐性死锁。
import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)
var rwMutex sync.RWMutex
//读时共享,写时独占
func readGo(in <- chan int,idx int)  {
	for {
		rwMutex.RLock()		//以读模式加锁
		num:=<-in
		fmt.Println("----%dth 读go程,读出:%d\n",idx,num)
		rwMutex.RUnlock()	//以读模式解锁
	}
}
func writeGo(out chan <- int,idx int)  {
	for {
		//生成随机数
		num := rand.Intn(1000)
		rwMutex.Lock()	//以写模式加锁
		out <- num
		fmt.Println("%dth 写Go程,写入:%d\n",idx,num)
		time.Sleep(time.Millisecond * 300)
		rwMutex.Unlock()	//以写模式解锁
	}
}
func main()  {
	//播种随机数种子
	rand.Seed(time.Now().UnixNano())
	ch:=make(chan int)		//用于 数据传递的channel
	for i:=0;i<5;i++ {
		go readGo(ch,i+1)
	}
	for i:=0;i<5;i++ {
		go writeGo(ch,i+1)
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值