Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why my golang channel raise dead lock error?

Tags:

go

package main

import (
    "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()
}

Output:

localhost:src kuankuan$ go run goroutine.go 
0 true
1 true
2 true
3 true
4 true
throw: all goroutines are asleep - deadlock!

goroutine 1 [semacquire]:
sync.runtime_Semacquire(0x42130100, 0x42130100)
    /usr/local/go/src/pkg/runtime/zsema_amd64.c:146 +0x25
sync.(*WaitGroup).Wait(0x42120420, 0x0)
    /usr/local/go/src/pkg/sync/waitgroup.go:79 +0xf2
main.main()
    /Users/kuankuan/go/src/goroutine.go:31 +0xb9

goroutine 2 [syscall]:
created by runtime.main
    /usr/local/go/src/pkg/runtime/proc.c:221
exit status 2
like image 546
WoooHaaaa Avatar asked Nov 26 '12 13:11

WoooHaaaa


People also ask

What are the differences between unbuffered and buffered channels?

An unbuffered channel is used to perform synchronous communication between goroutines while a buffered channel is used for perform asynchronous communication. An unbuffered channel provides a guarantee that an exchange between two goroutines is performed at the instant the send and receive take place.

What is a Goroutine?

A goroutine is a function that executes simultaneously with other goroutines in a program and are lightweight threads managed by Go. A goroutine takes about 2kB of stack space to initialize.

When deadlock occurs golang?

A deadlock happens when a group of goroutines are waiting for each other and none of them is able to proceed. For example: When one goroutine try to receive message from channel. And channel is empty.


1 Answers

The reason why it deadlocks is because structs are passed by value and not by reference.

When you pass the WaitGroup to your functions, you need to pass the pointer and not the value. Otherwise a copy of the WaitGroup will be used.

This is your working example:

package main

import (
    "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()
}
like image 184
ANisus Avatar answered Nov 16 '22 02:11

ANisus