ZBLOG

package main import ( "fmt" "sync" "time" ) func main() { channelCat := make(chan struct{}) channelDog := make(chan struct{}) channelFish := make(chan struct{}) channelCat

在你的代码中,出现死锁的原因是因为程序在等待信号的过程中没有正确地启动各个 goroutine,从而导致所有 goroutine 都无法继续执行。

具体来说,这里是你代码中的问题分析:

  1. 初始化通道:你首先向 channelCat 发送了一个值。这意味着 channelCat 现在有一个值,并且任何尝试从 channelCat 接收值的 goroutine 必须等待这个值被取走。

  2. Goroutines 的启动顺序

    • 第一个 goroutine 从 channelCat 中接收并打印 “cat”,然后向 channelDog 发送信号。
    • 第二个 goroutine 从 channelDog 中接收并打印 “dog”,然后向 channelFish 发送信号。
    • 第三个 goroutine 从 channelFish 中接收并打印 “fish”,然后再次向 channelCat 发送信号。
  3. 死锁情况

    • 当主函数创建并启动这些 goroutine 时,由于已经对 channelCat 写入了数据,第一个 goroutine 才能够执行并打印 “cat”。
    • 然后它会尝试向 channelDog 写入数据,但此时还没有任何 goroutine 在等待接收来自 channelDog 的数据,因此该操作将阻塞。
    • 此时,第二个和第三个 goroutines 等待前一个通道的数据,而第一个通道也因阻塞而无法继续,导致程序死锁。

如何修复

要解决这个问题,可以使用 buffered channel 来确保在通道满的时候不会导致阻塞。例如,你可以将通道声明为带缓冲区的:

package main

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

func main() {
	channelCat := make(chan struct{}, 1)
	channelDog := make(chan struct{}, 1)
	channelFish := make(chan struct{}, 1)

	channelCat <- struct{}{}

	wg := sync.WaitGroup{}
	wg.Add(3)

	go func() {
		defer wg.Done()
		<-channelCat
		fmt.Println("cat")
		time.Sleep(time.Second)
		channelDog <- struct{}{}
	}()

	go func() {
		defer wg.Done()
		<-channelDog
		fmt.Println("dog")
		time.Sleep(time.Second)
		channelFish <- struct{}{}
	}()

	go func() {
		defer wg.Done()
		<-channelFish
		fmt.Println("fish")
		time.Sleep(time.Second)
		channelCat <- struct{}{}
	}()
	
	wg.Wait()
}

这里,通过将每个通道设为带缓冲区的(buffered),即使没有其他 goroutines 在同时读取,也不会造成阻塞。这样一来,就可以避免因通道未准备好而导致的死锁。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=19921

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?