Home >Backend Development >Golang >How to Resolve Go Deadlocks Caused by Asynchronous Operations and Empty Channels?

How to Resolve Go Deadlocks Caused by Asynchronous Operations and Empty Channels?

Barbara Streisand
Barbara StreisandOriginal
2024-12-11 18:04:12244browse

How to Resolve Go Deadlocks Caused by Asynchronous Operations and Empty Channels?

Deadlock in Go: "all go routines are asleep"

When running the provided code, a deadlock occurs due to its asynchronous execution model using goroutines. The issue arises when the UnloadTrucks function is called before any trucks have been sent to the channel. This leads to the channel remaining empty, causing the sender goroutines to block at the line ch <- tr. Since the sender goroutines are waiting to send trucks, they cannot close the channel, and the UnloadTrucks function, which is waiting to receive trucks, is stuck indefinitely.

Solution: Using WaitGroup to Close Channel

To resolve the deadlock, we can close the channel ch after all goroutines have finished sending trucks. This can be achieved by introducing a WaitGroup, a synchronization primitive that tracks the number of pending goroutines:

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

This goroutine waits until all other goroutines have completed their tasks (signaled by the Wait() call) before closing the channel. By doing so, the UnloadTrucks function is able to exit gracefully when all trucks have been sent.

Revised Code:

package main

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

type Item struct {
    name string
}

type Truck struct {
    Cargo []Item
    name  string
}

func UnloadTrucks(c chan Truck) {

    for t := range c {
        fmt.Printf("%s has %d items in cargo: %s\n", t.name, len(t.Cargo), t.Cargo[0].name)
    }

}

func main() {
    trucks := make([]Truck, 2)

    ch := make(chan Truck)

    var wg sync.WaitGroup
    for i, _ := range trucks {

        trucks[i].name = fmt.Sprintf("Truck %d", i+1)

        fmt.Printf("Building %s\n", trucks[i].name)
    }

    for t := range trucks {
        go func(tr Truck) {

            itm := Item{}
            itm.name = "Groceries"

            fmt.Printf("Loading %s\n", tr.name)
            tr.Cargo = append(tr.Cargo, itm)
            ch <- tr
            wg.Done()

        }(trucks[t])
        wg.Add(1)
    }

    time.Sleep(50 * time.Millisecond)
    fmt.Println("Unloading Trucks")
    UnloadTrucks(ch)

    fmt.Println("Done")
}

With this modified code, the deadlock is eliminated because the UnloadTrucks function is guaranteed to receive all trucks before the channel is closed. This ensures that all goroutines complete their tasks properly and the program runs without any unexpected interruptions.

The above is the detailed content of How to Resolve Go Deadlocks Caused by Asynchronous Operations and Empty Channels?. 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