Home  >  Article  >  Backend Development  >  How can you avoid deadlock in Go when using WaitGroup and a channel with a limited buffer?

How can you avoid deadlock in Go when using WaitGroup and a channel with a limited buffer?

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-10-27 01:21:02959browse

How can you avoid deadlock in Go when using WaitGroup and a channel with a limited buffer?

Deadlock in Go with WaitGroup and Channel

In Go, a deadlock occurs when two or more goroutines wait indefinitely for the other to finish. In this example, we will explore a deadlock issue caused by an insufficient channel buffer and improper syncing of goroutines using a WaitGroup.

The Code

<code class="go">package main

import "fmt"
import "sync"

func main() {
    ch := make(chan []int, 4)
    var m []int

    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            ch <- m
            return
        }()
    }
    wg.Wait()

    for c := range ch {
        fmt.Printf("c is %v", c)
    }
}</code>

The Issue

The code attempts to send 5 values over a buffered channel of size 4. However, when the channel is full, it blocks until a receiver becomes available. Since all goroutines that are sending have finished, none are available to receive from the channel.

Additionally, the goroutine that ranges over the channel (for c := range ch) also remains blocked indefinitely because it expects more values to arrive in the channel even though no more are being sent. This creates a deadlock where both senders and receivers are waiting on each other.

Solution 1: Increase Channel Buffer and Close It

One solution to avoid the deadlock is to increase the channel buffer size to a value greater than or equal to the number of sending goroutines. Additionally, the channel should be closed after all sends are complete, indicating that no more values will be received.

<code class="go">ch := make(chan []int, 5)
...
wg.Wait()
close(ch)</code>

Solution 2: Perform Done() in Receiving Goroutine

Another solution is to perform Done() in the receiving goroutine instead of in the main function. By doing so, the WaitGroup will not be decremented until the value has been received and consumed by the goroutine:

<code class="go">func main() {
    ch := make(chan []int, 4)
    var m []int

    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func() {
            ch <- m
            return
        }()
    }
    go func() {
        for c := range ch {
            fmt.Printf("c is %v\n", c)
            wg.Done()
        }
    }()
    wg.Wait()
}</code>

The above is the detailed content of How can you avoid deadlock in Go when using WaitGroup and a channel with a limited buffer?. 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