zoukankan      html  css  js  c++  java
  • channel

    死锁

    
    package main
    
    import "fmt"
    
    func callerA(c chan string) {
    	c <- "Hello world! callerA"
    }
    
    func callerB(c chan string) {
    	c <- "Hello world! callerB"
    }
    
    func main() {
    	a, b := make(chan string), make(chan string)
    	go callerA(a)
    	go callerB(b)
    	for i := 0; i < 5; i++ {
    		select {
    		case msg := <-a:
    			fmt.Printf("%v from A
    ", msg)
    		case msg := <-b:
    			fmt.Printf("%v from B
    ", msg)
    		}
    	}
    }
    
    /*
    fatal error: all goroutines are asleep - deadlock!
    Hello worldBBBBBBBB! from B
    Hello world! from A
    
    goroutine 1 [select]:
    main.main()
    	C:/Users/zhourudong/go/src/awesomeProject/main.go:18 +0x19c
    */
    
    /*
    死锁原因:
    	当第一次循环时,main从a通道取值后,a通道为空;
    
    	当第二次循环时,main从b通道取值后,b通道为空;
    
    	当第三次循环时,main函数发现a/b通道都为空,callerA、callerB两个goroutine都已执行完毕,
    	a,b通道永远不会有值,main函数无止境的等待下去,go运行环境会抛出死锁错误
    
    */
    
    
    

    死锁解决

    package main
    
    import "fmt"
    
    func callerA(c chan string) {
    	c <- "Hello world! callerA"
    }
    
    func callerB(c chan string) {
    	c <- "Hello world! callerB"
    }
    
    func main() {
    	a, b := make(chan string), make(chan string)
    	go callerA(a)
    	go callerB(b)
    	for i := 0; i < 5; i++ {
    		select {
    		case msg := <-a:
    			fmt.Printf("%v from A
    ", msg)
    		case msg := <-b:
    			fmt.Printf("%v from B
    ", msg)
    		default:
    			fmt.Println("Default")
    		}
    	}
    }
    
    /*
    Default
    Hello world! callerB from B
    Hello world! callerA from A
    Default
    Default
    */
    
    /*
    输出 Default的原因是因为 
    通道还没有传入值,初始化完成,所以第一个只能输出Default
    
    解决方案:
    	休眠
    */
    
    
    // ---------------------------------------------------
    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func callerA(c chan string) {
    	c <- "Hello world! callerA"
    }
    
    func callerB(c chan string) {
    	c <- "Hello world! callerB"
    }
    
    func main() {
    	a, b := make(chan string), make(chan string)
    	go callerA(a)
    	go callerB(b)
    	for i := 0; i < 5; i++ {
    		time.Sleep(3 * time.Microsecond)
    		select {
    		case msg := <-a:
    			fmt.Printf("%v from A
    ", msg)
    		case msg := <-b:
    			fmt.Printf("%v from B
    ", msg)
    		default:
    			fmt.Println("Default")
    		}
    	}
    }
    
    /*
    Hello world! callerA from A
    Hello world! callerB from B
    Default
    Default
    Default
    */
    
    

    不使用sleep解决方案

    
    /*
    1、尝试向一个已关闭的通道发送信息会引发panic
    2、尝试关闭一个已关闭的通道也会触发panic
    3、尝试从一个已关闭的通道取值总得到一个与通道类型相对应的零值,
    	所以从已关闭的通道取值不会导致goroutine被阻塞
    */
    package main
    
    import "fmt"
    
    func callerA(c chan string) {
    	// 函数被调用后关闭
    	c <- "Hello world callerA"
    	close(c)
    }
    func callerB(c chan string) {
    	// 函数被调用后关闭
    	c <- "Hello world callerB"
    	close(c)
    }
    
    func main() {
    	a, b := make(chan string), make(chan string)
    	go callerA(a)
    	go callerB(b)
    
    	var msg string
    	ok1, ok2 := true, true
    
    	for ok1 || ok2 {
    		select {
    		case msg, ok1 = <-a: //  通道取出的值会赋值给msg,ok1则表示通道已经关闭则被设置成false
    			if ok1 {
    				fmt.Printf("%s from A
    ", msg)
    			}
    		case msg, ok2 = <-b:
    			if ok2 {
    				fmt.Printf("%s from B
    ", msg)
    			}
    
    		}
    	}
    }
    
    
    /*
    1、尝试向一个已关闭的通道发送信息会引发panic
    2、尝试关闭一个已关闭的通道也会触发panic
    3、尝试从一个已关闭的通道取值总得到一个与通道类型相对应的零值,
    	所以从已关闭的通道取值不会导致goroutine被阻塞
    */
    package main
    
    import (
    	"fmt"
    )
    
    func callerA(c chan int) {
    	// 函数被调用后关闭
    	c <- 1111
    	close(c)
    }
    
    func main() {
    	a := make(chan int)
    	go callerA(a)
    
    	var ok bool
    	var msg int
    
    	msg, ok = <-a // 第一次通道还没有关闭 返回值和一个布尔值,
    
    	fmt.Println(msg, ok)
    
    	msg, ok = <-a // 通道已关闭, 得到与通道相对应类型的零值,一个为false的布尔值
    	fmt.Println(msg, ok)
    
    }
    
    /*
    1111 true
    0 false
    */
    
    
  • 相关阅读:
    Sublime Text 在同一窗口同时显示多个项目文件夹
    前端之PS切图
    Sublime Text 菜单栏消失问题
    php中的排序算法
    vim 108上下左右键失效?
    写一个自己的markdown解析器
    2016.年末总结
    闭包
    JavaScript事件委托
    const参数,const返回值与const函数
  • 原文地址:https://www.cnblogs.com/zrdpy/p/8637989.html
Copyright © 2011-2022 走看看