Home > Back-end >  fatal error: all goroutines are asleep - deadlock | Go Routine
fatal error: all goroutines are asleep - deadlock | Go Routine

Time:01-28

The problem is that both the goOne and goTwo functions are sending values to the channels ch1 and ch2 respectively, but there is no corresponding receiver for these values in the main function. This means that the channels are blocked and the program is unable to proceed. As a result, the select statement in the main function is unable to read from the channels, so it always executes the default case.

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    ch1 := make(chan string)
    ch2 := make(chan string)

    wg.Add(2)
    go goOne(&wg, ch1)
    go goTwo(&wg, ch2)

    select {
    case <-ch1:
        fmt.Println(<-ch1)
        close(ch1)

    case <-ch2:
        fmt.Println(<-ch2)
        close(ch2)

    default:
        fmt.Println("Default Case")
    }
    wg.Wait()

}

func goTwo(wg *sync.WaitGroup, ch2 chan string) {
    ch2 <- "Channel 2"
    wg.Done()
}

func goOne(wg *sync.WaitGroup, ch1 chan string) {
    ch1 <- "Channel 1"
    wg.Done()
}

Output:

Default Case
fatal error: all goroutines are asleep - deadlock!

goroutine 1 \[semacquire\]:
sync.runtime_Semacquire(0xc000108270?)
/usr/local/go/src/runtime/sema.go:62  0x25
sync.(\*WaitGroup).Wait(0x4b9778?)
/usr/local/go/src/sync/waitgroup.go:139  0x52
main.main()
/home/nidhey/Documents/Go_Learning/goroutines/select.go:29  0x2af

goroutine 6 \[chan send\]:
main.goOne(0x0?, 0x0?)
/home/nidhey/Documents/Go_Learning/goroutines/select.go:39  0x28
created by main.main
/home/nidhey/Documents/Go_Learning/goroutines/select.go:14  0xc5

goroutine 7 \[chan send\]:
main.goTwo(0x0?, 0x0?)
/home/nidhey/Documents/Go_Learning/goroutines/select.go:33  0x28
created by main.main
/home/nidhey/Documents/Go_Learning/goroutines/select.go:15  0x119\```

I'm looking for a different pattern such as select to handle the case when the channels are blocked.

To fix the issue, I've added a <-ch1 or <-ch2 in the main function after wg.Wait() to receive the values sent to the channels and unblock them

CodePudding user response:

It's not entirely clear what you want to do. If you want to wait for both goroutines to complete their work and get the result of their work into the channel, you don't need a weight group (because it won't be reached).

You can do something like this.

package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)

    go goOne(ch1)
    go goTwo(ch2)

    for {
        select {
        case v := <-ch1:
            fmt.Println("Done ch1:", v)
            ch1 = nil
        case v := <-ch2:
            fmt.Println("Done ch2:", v)
            ch2 = nil
        case <-time.After(time.Second):
            fmt.Println("I didn't get result so lets skip it!")
            ch1, ch2 = nil, nil
        }
        if ch1 == nil && ch2 == nil {
            break
        }
    }
}

func goTwo(ch chan string) {
    ch <- "Channel 2"
}

func goOne(_ chan string) {
    //ch1 <- "Channel 1"
}

CodePudding user response:

Firstly you have a race condition in that your channel publishing goroutines will probably not have been started by the time you enter the select statement, and it will immediately fall through to the default.

But assuming you resolve this (e.g. with another form of semaphore) you're on to the next issue - your select statement will either get chan1 or chan2 message, then wait at the bottom of the method, but since it is no longer in the select statement, one of your messages won't have arrived and you'll be waiting forever.

You'll need either a loop (twice in this case) or a receiver for both channels running in their own goroutines to pick up both messages and complete the waitgroup.

But in any case - as others have queried - what are you trying to achieve?

CodePudding user response:

You can try something like iterating over a single channel (assuming both channels return the same type of data) and then count in the main method how many tasks are completed. Then close the channel once all the tasks are done. Example:

package main

import (
    "fmt"
)

func main() {
    ch := make(chan string)

    go goOne(ch)
    go goTwo(ch)
    doneCount := 0

    for v := range ch {
        fmt.Println(v)
        doneCount  
        if doneCount == 2 {
            close(ch)
        }
    }
}

func goTwo(ch chan string) {
    ch <- "Channel 2"
}

func goOne(ch chan string) {
    ch <- "Channel 1"
}
  • Related