欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

4.5 并发技术5:死锁问题

程序员文章站 2022-05-22 11:20:27
...

1. 同一个goroutine中,使用同一个 channel 读写

package main
func main(){
    ch:=make(chan int)  //这就是在main程里面发生的死锁情况
    ch<-6   //  这里会发生一直阻塞的情况,执行不到下面一句
    <-ch
}

这是最简单的死锁情况
看运行结果
4.5 并发技术5:死锁问题

1. 2个 以上的go程中, 使用同一个 channel 通信。 读写channel 先于 go程创建。

 package main

func main(){
    ch:=make(chan int)
    ch<-666    //这里一直阻塞,运行不到下面
    go func (){
        <-ch  //这里虽然创建了子go程用来读出数据,但是上面会一直阻塞运行不到下面
    }()
}

这里如果想不成为死锁那匿名函数go程就要放到ch<-666这条语句前面
4.5 并发技术5:死锁问题

3. 2个以上的go程中,使用多个 channel 通信。 A go 程 获取channel 1 的同时,尝试使用channel 2, 同一时刻,B go 程 获取channel 2 的同时,尝试使用channel 1

package main
func main()  {
    ch1 := make(chan int)
    ch2 := make(chan int)
    go func() {    //匿名子go程
        for {
            select {    //这里互相等对方造成死锁
            case <-ch1:   //这里ch1有数据读出才会执行下一句
                ch2 <- 777
            }
        }
    }()
    for {         //主go程
        select {
        case <-ch2 : //这里ch2有数据读出才会执行下一句
            ch1 <- 999
        }
    }
}

第三种是互相等对方造成死锁

4.注意读写模式的锁定不要互相阻塞

  • 隐形死锁:系统的两个或多个任务之间互相阻塞对方,形成事实上的死锁局面,然而只要有可运行的协程,编译器就不会显式地报死锁错误——这就是隐形死锁;
  • 开发中真正可怕的不是显式的死锁,而是隐形死锁;
func main() {

	var rwm09 sync.RWMutex
	ch := make(chan int, 0)

	//子协程负责写入
	go func() {
		//连锁都抢不到555...
		rwm09.Lock()
		ch <- 123
		rwm09.Unlock()
	}()

	go func() {
		//本协程负责读出
		rwm09.RLock()
		//只要读不到内容就永远阻塞
		x := <- ch
		fmt.Println("读到",x)
		rwm09.RUnlock()
	}()

	for {
		//通知垃圾回收器来清理垃圾(即使不叫也会定时清理)
		runtime.GC()
	}

}
相关标签: 死锁问题