Trouble with unbuffered channel in Go

I am trying to simulate a very simple synchronous message-passing system with a broker. The broker has a channel where the client writes on it and the server is supposed to read from it.

Here is the code:

package main

import (
    "fmt"
    "strconv"
)

type Broker struct {
    ch chan string
}

var broker Broker

func runClient() {
    for i := 1; i <= 6; i++ {
        message := strconv.Itoa(i)
        fmt.Println("CLIENT: sent " + message + " to channel")
        broker.ch <- message
    }
    close(broker.ch)
}

func runServer() {
    for message := range broker.ch {
        fmt.Println("SERVER: received " + message + " from channel")
    }
}

func main() {
    broker.ch = make(chan string)
    go runClient()
    runServer()
}

Since the size of the channel buffer is zero, I am expecting the code to block on broker.ch <- message until this message is read by the other goroutine (the server). However, the output is this:

CLIENT: sent 1 to channel
CLIENT: sent 2 to channel
SERVER: received 1 from channel
SERVER: received 2 from channel
CLIENT: sent 3 to channel
CLIENT: sent 4 to channel
SERVER: received 3 from channel
SERVER: received 4 from channel
CLIENT: sent 5 to channel
CLIENT: sent 6 to channel
SERVER: received 5 from channel
SERVER: received 6 from channel

The output I was expecting to get was:

CLIENT: sent 1 to channel
SERVER: received 1 from channel
CLIENT: sent 2 to channel
SERVER: received 2 from channel
CLIENT: sent 3 to channel
SERVER: received 3 from channel
CLIENT: sent 4 to channel
SERVER: received 4 from channel
CLIENT: sent 5 to channel
SERVER: received 5 from channel
CLIENT: sent 6 to channel
SERVER: received 6 from channel

It seems that the buffer has a capacity of one instead of zero. Where am I making a mistake? How can I change the code to get the second output?

Hi @daneshvar.amrollahi,

I guess the reason is that the client prints before accessing the channel, and the server prints after accessing it.

The concurrent setup itself looks correct to me.

1 Like

Hi @christophberger

Thanks for the reply. I see. Is there any way to verify that my code is behaving as I’m expecting it to? In other words, can I see this synchronous/blocking behavior (waiting for the server to read from the channel) using print statements or any other thing?

If you really want to observe the exact sequence of action, I guess you would need to treat the two operations (print + channel operation) as a critical section and guard them with a common mutex. Then, only either of the sender or receiver can do the channel operation and print its progress.

But then, why would you need to verify that the channel operation is blocking? The blocking happens by design, there is no way that the read or write operation on an unbuffered channel does not block until the other side is ready to write or read as well.

1 Like

thanks for the awesome information.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.