我使用了sync包,但在Golang中遇到了死锁错误;(

huangapple go评论90阅读模式
英文:

I used sync package but I get Deadlock error in Golang ;(

问题

你的代码出现了死锁的情况。死锁是指两个或多个goroutine在相互等待对方释放资源时无法继续执行的情况。

在你的代码中,你创建了一个无缓冲的通道c,然后在main函数中启动了一个goroutine来向通道写入数据。但是在写入数据之后,你没有从通道中读取数据,导致该goroutine一直阻塞在写入操作上。同时,主goroutine在等待waitGroup中的计数器归零,但由于子goroutine无法继续执行,计数器无法减少,从而导致了死锁。

要解决这个问题,你可以在main函数中添加一个从通道中读取数据的操作,以确保goroutine能够继续执行。你可以使用range循环来读取通道中的数据,直到通道关闭为止。修改后的代码如下所示:

package main

import (
	"fmt"
	"sync"
)

var waitGroup sync.WaitGroup

func writeToChannel(c chan int, x int) {
	defer waitGroup.Done()

	fmt.Println(x)
	c <- x // 向通道写入数据
	fmt.Println(x)
}

func main() {
	c := make(chan int)

	waitGroup.Add(1)
	go writeToChannel(c, 10)

	go func() {
		defer waitGroup.Done()

		for value := range c {
			fmt.Println("Received:", value)
		}
	}()

	waitGroup.Wait()
	close(c)
}

这样修改后的代码会先启动一个goroutine来读取通道中的数据,然后再启动一个goroutine来向通道写入数据。主goroutine会等待waitGroup中的计数器归零,并在最后关闭通道。

这样修改后,你的代码就不会再出现死锁的情况了。

英文:

I was so excited that I wrote a Go code to learn goroutine.

And then

In the process of learning goroutine, I applied the sync package and channel to generate the following code.

package main

import (
	&quot;fmt&quot;
	&quot;sync&quot;
)


var waitGroup sync.WaitGroup

func writeToChannel(c chan int, x int) {

	fmt.Println(x)
	c &lt;- x // c라는 채널에 x값을 쓴다.
	fmt.Println(x)
	close(c) // 통신 종료

	waitGroup.Done()
}

func main() {

	c := make(chan int)

	waitGroup.Add(1)
	go writeToChannel(c, 10)
	waitGroup.Wait()

}

After that, I compiled it, but the following error occurred.

junbeomhan@acd:~/Documents/workspace/go/src/go-routine$ go run writeCh.go 
10
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc000014270?)
        /usr/local/go/src/runtime/sema.go:62 +0x27
sync.(*WaitGroup).Wait(0x0?)
        /usr/local/go/src/sync/waitgroup.go:116 +0x4b
main.main()
        /home/junbeomhan/Documents/workspace/go/src/go-routine/writeCh.go:22 +0x85

goroutine 6 [chan send]:
main.writeToChannel(0x0?, 0xa)
        /home/junbeomhan/Documents/workspace/go/src/go-routine/writeCh.go:12 +0x75
created by main.main
        /home/junbeomhan/Documents/workspace/go/src/go-routine/writeCh.go:21 +0x79
exit status 2

What's wrong with my code?

答案1

得分: 3

c := make(chan int) 你声明了一个无缓冲通道,所以如果没有消费者消费这个通道,生产者将被阻塞。因此,go writeToChannel(c, 10) 的 goroutine 在 c <- x // c라는 채널에 x값을 쓴다. 处被阻塞,无法执行 waitGroup.Done()。而主 goroutine 被 waitGroup 阻塞,所以发生了死锁。

为了使这段代码工作,你可以简单地从主 goroutine 中消费这个无缓冲通道。

func main() {
	c := make(chan int)
	waitGroup.Add(1)
	go writeToChannel(c, 10)
	num := <-c // 新代码在这里
	fmt.Printf("接收到的数字:%d", num)
	waitGroup.Wait()
}

https://go.dev/play/p/1FzQu0-MxJG

英文:

c := make(chan int) You declared an unbuffered channel, so if there are no consumers consuming this channel, the producer will be blocked. So go writeToChannel(c, 10) goroutine is blocked at c &lt;- x // c라는 채널에 x값을 쓴다., can not execute waitGroup.Done(). And the main goroutine is blocked by waitGroup, so deadlock occured.

To make this code work, you can just simply consume this unbuffered channel from main goroutine.


func main() {

	c := make(chan int)

	waitGroup.Add(1)
	go writeToChannel(c, 10)
	num := &lt;-c // new code here
	fmt.Printf(&quot;num received %d&quot;, num)
	waitGroup.Wait()

}

https://go.dev/play/p/1FzQu0-MxJG

答案2

得分: 0

记住这个:对于一个非缓冲通道,在一个goroutine中读取/写入通道时,你需要另一个goroutine来从同一个通道中读取/写入。

如果上述情况没有发生,你将会遇到死锁。

在你的情况下,你在goroutine中写入通道,但是你在哪里读取它没有地方

要解决这个问题,你只需要在启动goroutine后立即从通道中读取。即:

func main() {

    c := make(chan int)

    waitGroup.Add(1)
    go writeToChannel(c, 10)
    <- c // 从通道中读取以避免死锁
    waitGroup.Wait()

}
英文:

Remember this: For an unbuffered channel, when you are reading/writing to a channel in a goroutine then you need another goroutine to write/read from the same channel.

If the above is not happening, you'll have a deadlock.

In your case you are writing to the channel in the goroutine but where are you reading it? Nowhere.

To fix this, you just need to read from the channel right after you kick off the goroutine. I.e.

func main() {

    c := make(chan int)

    waitGroup.Add(1)
    go writeToChannel(c, 10)
    &lt;- c // read from the channel to avoid deadlock
    waitGroup.Wait()

}

huangapple
  • 本文由 发表于 2023年7月14日 11:26:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76684523.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定