• GO语言信道(channel)--几种死锁情况


    什么是信道

    信道是go协成之间的通信管道, 所有的信道都关联了一个类型, 信道只能运输这种类型的数据, 运输其他类型的数据会报错

    chan T 表示 T 类型的信道。

    信道的零值为 nil。信道的零值没有什么用,通常用 make 来定义信道。例如:

      a := make(chan int) 声明一个类型为int的信道,长度默认为0

    信道进行发送和接收

    data := <- a   //表示从信道a读取数据, 也就是信道发送数据
    a <- data  //表示向信道a存入数据, 也就是信道接收数据

    信道的发送和接收默认是阻塞的, 当数据发送到信道时, 如果信道长度为0, 则会发生阻塞, 直到有其他go协程从该信道读取数据, 阻塞才会解除, 同样从信道读取数据也会发生阻塞, 例如: 

    package main
    
    func main() {
    	a := make(chan int)
    	a <- 1
    }

     在上面程序中, 我们声明了一个长度为0的信道,  ch := make(chan type, capacity) capacity不写默认为0, 程序会在a <-1 发生死锁, 运行程序触发panic, 运行错误如下:

    fatal error: all goroutines are asleep - deadlock!
    
    goroutine 1 [chan send]:
    main.main()
    	/home/yxh/learn/go/test/hello.go:5 +0x50

    但是如果改变信道的长度, 比如a := make(chan int, 1) , 程序就可以正常运行

    信道死锁

    当 Go 协程给一个信道发送数据时,照理说会有其他 Go 协程来接收数据。如果没有的话,程序就会在运行时触发 panic,形成死锁。

     死锁的几种情况:
    1.主协程读写:

    package main
    
    func main() {
    	a := make(chan int)
    	a <- 1
    	<-a
    }

    这种是最简单的死锁情况, 程序运行到a <- 1就发生了死锁, <- a其实运行不到, 程序最终发生panic, 如果将信道的声明改成a := make(chan int, 1), 则程序会正常运行

    2.主协程写, 子协程读 --- 主协程读, 子协程写

    package main
    
    func main() {
    	a := make(chan int)
    	a <- 1
    	go func() {
    		<-a
    	}()
    }

    这种情况虽然读和写不在同一个协程, 但是由于主协程在a <- 1的时候就发生了死锁, 程序根本运行不到子协程, 所以go func根本就没有运行, 如果调换一下位置, 程序就可以正常运行, 不会发生panic了:

    package main
    
    func main() {
    	a := make(chan int)
    	go func() {
    		<-a
    	}()
    	a <- 1
    }

    调换位置后, 程序先开启子协程, 读取信道的数据, 此时子协程发生死锁, 但是这并不影响主协程的运行, 所以主协程照常运行
    3.字协程读写多个信道, 顺序和主协程不一致

    package main
    
    func main() {
    	c1, c2 := make(chan int), make(chan int)
    	go func() {
    		<-c1
    		<-c2
    	}()
    	for {
    		c2 <- 10
    		c1 <- 10
    	}
    }

    上述代码中, 子协程依次读取c1, 和c2信道, 但是子协程在<- c1处就发生阻塞, 主协程依次往c2,c1信道写入数据, 由于没有其他协程读取c2信道的数据, 所以主协程会在c2 <- 10处发生阻塞, 两处阻塞都无法解除, 最终主协程死锁, 发生pamic

    死锁的情况有很多种, 这里出现的几种不是说一定会出现死锁, 有的你只要修改下信道的长度, 也许就不会发生死锁了, 发生死锁只是发生在特定情况

     
  • 相关阅读:
    指针
    day07
    day06
    oracle instr
    动态解析dll及使用类
    客户端调用接口
    Java中调用WebService
    Vs2015智能提示英文
    oracle中varchar(32)转nvarchar(32)
    C#创建XML节点
  • 原文地址:https://www.cnblogs.com/y-yxh/p/12941408.html
Copyright © 2020-2023  润新知