Home  >  Article  >  Backend Development  >  How to Avoid Deadlock in Go Goroutines When Producers Are Short-Lived?

How to Avoid Deadlock in Go Goroutines When Producers Are Short-Lived?

Linda Hamilton
Linda HamiltonOriginal
2024-10-25 07:09:02784browse

How to Avoid Deadlock in Go Goroutines When Producers Are Short-Lived?

Resolving Deadlock in Go Goroutines

In concurrent programming, deadlock occurs when multiple goroutines wait indefinitely for each other to complete operations, effectively halting the program. This article addresses a specific deadlock encountered in Go concurrency, as described in the original question:

<code class="go">package main

import (
    "fmt"
    "time"
)

func producer(ch chan int, d time.Duration, num int) {
    for i := 0; i < num; i++ {
        ch <- i
        time.Sleep(d)
    }
}

func main() {
    ch := make(chan int)
    go producer(ch, 100*time.Millisecond, 2)
    go producer(ch, 200*time.Millisecond, 5)
    for {
        fmt.Println(<-ch)
    }
    close(ch)
}</code>

This code triggers a deadlock error due to the following factors:

  • The producers, which send values to the channel, are short-lived and eventually stop producing data.
  • The endless for loop in the main function continuously receives values from the channel without a termination condition.
  • The channel is closed after the endless loop, resulting in no further values being available for receiving.

Solution: Coordinated Termination

To avoid deadlock, the producers must be coordinated to signal completion, and the channel must be closed by the last producer. Here's an efficient solution using a sync.WaitGroup for coordination:

<code class="go">func producer(ch chan int, d time.Duration, num int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < num; i++ {
        ch <- i
        time.Sleep(d)
    }
}

func main() {
    wg := &sync.WaitGroup{}
    ch := make(chan int)

    wg.Add(1)
    go producer(ch, 100*time.Millisecond, 2, wg)
    wg.Add(1)
    go producer(ch, 200*time.Millisecond, 5, wg)

    go func() {
        wg.Wait()
        close(ch)
    }()

    for v := range ch {
        fmt.Println(v)
    }
}</code>

In this solution:

  • We increment the WaitGroup for each producer.
  • Each producer decrements the WaitGroup upon completion through a defer statement.
  • A goroutine waits for the WaitGroup to reach zero (meaning all producers are done) and closes the channel.
  • The main loop uses a for range construct to iterate over the values sent on the channel before it is closed.

The above is the detailed content of How to Avoid Deadlock in Go Goroutines When Producers Are Short-Lived?. 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