go 为什么这样的代码会产生死锁问题

2022-02-11 00:10:46 +08:00
 proxytoworld

按道理 main 结束之前启动的 goroutine 不会结束,如果不发送 stopCh ,则会一直阻塞,为啥会提示有死锁

package main

import (
	"fmt"
	"sync"
	"time"
)

var wg sync.WaitGroup

func main() {
	fmt.Print("hello world\n")
	ch1 := make(chan int)
	ch2 := make(chan int)
	stopCh := make(chan struct{})
	wg.Add(1)
	go work(ch1, ch2, stopCh)
	ch1 <- 1
	ch2 <- 1
	time.Sleep(1000 * time.Millisecond)
	// stopCh <- struct{}{}
	var a int

	wg.Wait()
	fmt.Scan(&a)
}
func work(ch1, ch2 chan int, stopCh <-chan struct{}) {
	defer wg.Done()
	for {
		select {
		case <-stopCh:
			return
		case job1 := <-ch1:
			fmt.Println("receive ch1 on first loop:", job1)
		case job2 := <-ch2:
		priority:
			for {
				select {
				case job1 := <-ch1:
					fmt.Println("receive ch1 on second loop:", job1)
				default:
					time.Sleep(1000 * time.Millisecond)
					break priority
				}
			}
			// 执行 job1 的内容
			fmt.Println("receive ch2:", job2)
		}
	}
}


运行之后报错

hello world
receive ch1 on first loop: 1
receive ch2: 1
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xd77c28)
        C:/go/src/runtime/sema.go:56 +0x49
sync.(*WaitGroup).Wait(0xd77c20)
        C:/go/src/sync/waitgroup.go:130 +0x6b
main.main()
        F:/code/go/c2c/client/client.go:24 +0x1b6

goroutine 6 [select]:
main.work(0xc000014180, 0xc0000141e0, 0xc000014240)
        F:/code/go/c2c/client/client.go:30 +0x26e
created by main.main
        F:/code/go/c2c/client/client.go:17 +0x146
exit status 2

1520 次点击
所在节点    问与答
11 条回复
quzard
2022-02-11 00:32:53 +08:00
你的 work 被阻塞休眠了。然后导致已有的 goroutine 都处于休眠状态,导致报错了
quzard
2022-02-11 00:35:15 +08:00
WaitGroup 永远不会被通知 done ,造成了异常
lianyue
2022-02-11 00:36:43 +08:00
进了
job2 := <-ch2
就不能退出了
永远都在里面
CEBBCAT
2022-02-11 00:50:24 +08:00
楼主的第一句话看得不是很懂,work 的第一个 for 也没看见能主动退出的地方啊
ch2
2022-02-11 01:46:43 +08:00
建议先把名字取好,没人愿意看一堆 c1 、c2 不知干啥用的变量名
lovelylain
2022-02-11 08:19:35 +08:00
stopCh <- struct{}{}被你注释了,main 阻塞在 wg.Wait(),work 阻塞在 select ,没其他 goroutine 在活动能改变这俩阻塞状态。
awalkingman
2022-02-11 09:42:24 +08:00
@ch2 你这昵称很应景哈哈哈哈哈
proxytoworld
2022-02-11 14:25:34 +08:00
@CEBBCAT 在里面有 return 这个协程会退出 如果收到 stopCh
proxytoworld
2022-02-11 14:25:52 +08:00
@ch2 测试用例 所以没取名
proxytoworld
2022-02-11 14:26:29 +08:00
@jobmailcn 懂了
CEBBCAT
2022-02-14 12:58:04 +08:00
推荐楼主学习一下《银行家算法》

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/833080

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX