为啥以下代码会产生deadlock?

linture · 2019-08-22 23:36:02 · 990 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2019-08-22 23:36:02 的主题,其中的信息可能已经有所发展或是发生改变。

import (
    "fmt"
)

func main() {
    AlterPrint()
}

// POINT: communicate between goroutines by channel

func AlterPrint(){
  letter, number := make(chan bool), make(chan bool)
  letterDone := make(chan bool)
  numberDone := make(chan bool)
  go func() {
    i := 1
    for {
      if i > 28 {
          numberDone <- true
          return
      }
      select{
        case <-number: {
          fmt.Print(i)
          i++
          fmt.Print(i)
          i++
          letter <- true
          break
        }
        default: {
          break
        }
      }

    }
  }()

  go func(){
    i := 'A'
    for {
      if i > 'Z' {
        letterDone <- true
        return
      }
      select{
        case <-letter: {
          fmt.Print(string(i))
          i++
          fmt.Print(string(i))
          i++
          number <- true
          break
        }
        default: {
          break
        }
      }
    }
  }()
  number <- true
  <- letterDone
  <- numberDone
}

I expect the output of "12AB34CD56EF78GH910IJ1112KL1314MN1516OP1718QR1920ST2122UV2324WX2526YZ2728", but the actual output is

goroutine 1 [chan receive]:
main.AlterPrint()
    /tmp/54841538.go:66 +0x183
main.main()
    /tmp/54841538.go:7 +0x14

goroutine 5 [chan send]:
main.AlterPrint.func1(0xc82000c240, 0xc82000c180, 0xc82000c120)
    /tmp/54841538.go:31 +0x25a
created by main.AlterPrint
    /tmp/54841538.go:40 +0xde
exit status 2

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

990 次点击  
加入收藏 微博
3 回复  |  直到 2019-08-26 10:38:12
StoneFlying
StoneFlying · #1 · 6年之前
package main

import (
    "fmt"
)

func main() {
    AlterPrint()
}

// POINT: communicate between goroutines by channel

func AlterPrint(){
  letter, number := make(chan bool), make(chan bool)
  letterDone := make(chan bool)
  numberDone := make(chan bool)
  go func() {
    i := 1
    for {
      if i > 28 {
          numberDone <- true
          return
      }
      select{
        case <-number: {
          fmt.Print(i)
          i++
          fmt.Print(i)
          i++
          if i != 29 {
              letter <- true
          }
          break
        }
        default: {
          break
        }
      }

    }
  }()

  go func(){
    i := 'A'
    for {
      if i > 'Z' {
        letterDone <- true
        return
      }
      select{
        case <-letter: {
          fmt.Print(string(i))
          i++
          fmt.Print(string(i))
          i++
          number <- true
          break
        }
        default: {
          break
        }
      }
    }
  }()
  number <- true
  <- letterDone
  <- numberDone
}
stayfoo
stayfoo · #2 · 6年之前

1、两个goroutine中的代码,在互相等待 chan 的值

numberletter 永远不会接收到数据,导致 numberDone 和 letterDone 也永远不会接收到数据。

case <-number: {
                fmt.Print(i)
                i++
                fmt.Print(i)
                i++
                letter <- true
                break
            }
case <-letter: {
                fmt.Print(string(i))
                i++
                fmt.Print(string(i))
                i++
                number <- true
                break
            }

2、发送到 chan 的数据,没有被接收。

main 中最后 number <- true ,发送给 number 了一个true,没有被接收。

使用如下代码就不会崩溃:

number <- true
fmt.Println("number: ", <- number)
linture
linture · #3 · 6年之前

Solved. letterDone 被读出之后,第二个goroutine完全退出,第一个goroutine阻塞在了letter <- true,主线程阻塞在了<- numberDone。@StoneFlying's answer solved this dead lock.

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传