Troskyvs
Troskyvs

Reputation: 8087

does unbuffered channel wait for data?

I have this program:

package main

import (
    "fmt"
    "time"
)

var ch1 = make(chan int)
var ch2 = make(chan int)

func f1() {
    select {
    case <-ch1:
        fmt.Println("ch1")
    }
}
func f2() {
    select {
    case <-ch2:
        fmt.Println("ch2")
    }
}
func main() {
    go f1()
    go f2()
    time.Sleep(2 * time.Second)
    fmt.Println("no buffered channel will wait?")
    ch1 <- 1
    ch2 <- 2
    fmt.Println("main exits")
}

I expect that, as long as f1 and f2 doesn't print anything, it means ch1 and ch2 has nothing inside, so ch1<-1 and ch2<-2 should block?

But when run, it prints:

no buffered channel will wait?
main exits

Why those unbuffered channels ch1 and ch2 were not blocked within main?

If I don't call f1/f2 in main, it will report a dead lock error.

I don't understand what f1/f2 have done to ch1/ch2.

Would you kindly help to explain their behavior?

Upvotes: 0

Views: 342

Answers (1)

icza
icza

Reputation: 418455

Both f1() and f2() have receive operations. These are blocking operations: as long as there is nobody sending anything on the channel, they wait.

So you launch f1() and f2() as new goroutines, and main() sleeps. Meanwhile f1() and f2() are waiting for data from ch1 and ch2.

Then main() wakes up, and tries to send a value on ch1. This is OK because there is a goroutine ready to receive from it (f1()). Then main() tries to send on ch2, this is also OK, there is f2() ready to receive from it.

Then main() returns, and app ends (it does not wait for the other goroutines to print).

If you don't launch f1() and f2() as new goroutines, when main() reaches the send statements, there will be nobody ready to receive from the channels, and since it is unbuffered, it will block. And since there won't be any more goroutines running, this is a deadlock.

Upvotes: 7

Related Questions