Home  >  Article  >  Backend Development  >  Why does passing a WaitGroup by value in Go channels lead to a deadlock?

Why does passing a WaitGroup by value in Go channels lead to a deadlock?

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-10-31 04:59:02375browse

Why does passing a WaitGroup by value in Go channels lead to a deadlock?

Deadlock in Go Channel Due to Reference Passing

In Go, channels are a powerful communication mechanism, but they can lead to deadlocks if not used correctly. A deadlock occurs when two or more goroutines are waiting for each other to complete an operation, resulting in neither goroutine being able to proceed.

Consider the following Go program:

<br>package main</p>
<p>import (</p>
<pre class="brush:php;toolbar:false">"fmt"
"sync"

)

func push(c chan int, wg sync.WaitGroup) {

for i := 0; i < 5; i++ {
    c <- i
}
wg.Done()

}

func pull(c chan int, wg sync.WaitGroup) {

for i := 0; i < 5; i++ {
    result, ok := <-c
    fmt.Println(result, ok)
}
wg.Done()

}

func main() {

var wg sync.WaitGroup
wg.Add(2)
c := make(chan int)

go push(c, wg)
go pull(c, wg)

wg.Wait()

}

When you run this program, it will panic with a deadlock error:

throw: all goroutines are asleep - deadlock!

The problem lies in how the WaitGroup is passed to the goroutines. In Go, structs are passed by value, which means that a copy of the WaitGroup is passed to each goroutine. When one goroutine calls Done on its copy, it has no effect on the original WaitGroup that was created in the main function.

To fix the deadlock, the WaitGroup pointer must be passed instead of the value. Here's the corrected code:

<br>package main</p><p>import (</p><pre class="brush:php;toolbar:false">"fmt"
"sync"

)

func push(c chan int, wg *sync.WaitGroup) {

for i := 0; i < 5; i++ {
    c <- i
}
wg.Done()

}

func pull(c chan int, wg *sync.WaitGroup) {

for i := 0; i < 5; i++ {
    result, ok := <-c
    fmt.Println(result, ok)
}
wg.Done()

}

func main() {

var wg sync.WaitGroup
wg.Add(2)
c := make(chan int)

go push(c, &wg)
go pull(c, &wg)

wg.Wait()

}

By passing the WaitGroup pointer instead of the value, both goroutines have access to the same WaitGroup instance. When one goroutine calls Done, it decrements the count on the original WaitGroup, allowing the other goroutine to proceed.

The above is the detailed content of Why does passing a WaitGroup by value in Go channels lead to a deadlock?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn