Good afternoon, I had a question about the use of channels in golang, more precisely, how to determine that the channel is closed. Here is an example:

package main import ( "fmt" "time" ) func run () chan string { c := make(chan string) i := 0 go func() { fmt.Println("Init loop") for { i++ msg := fmt.Sprintf("Message #%d", i) fmt.Println("Send:", msg) select { case c <- msg: fmt.Println("Sent message") default: fmt.Println("default?") } time.Sleep(time.Millisecond * 1500) } fmt.Println("Shutdown loop") }() return c } func main() { c := run() for i:= 1; i < 10; i++ { if i == 5 { fmt.Println("Close input chan") close(c) } fmt.Printf("Receive #%d: '%s'\n", i, <-c) } } 

link to the code https://repl.it/ENFk/0 Actually the question is, if the channel were closed (line 34), the control was transferred to the "Shutdown loop"

  • PS All this is done in order to correctly stop goroutone in run (). About the use of semaphores and channels for this - in the know. The question is, is it possible for this to use the outgoing channel itself - chernomyrdin

1 answer 1

The closed channel is not blocked for reading. Special design

 Loop: for { select { case val, ok :=<- someChan: if !ok { // канал закрыт break Loop } // получены данные, работа с val default: // канал пуст, что-то делать } } 

In this case, ok will be true only for an open channel. But when you close the channel, you will receive empty messages all the time and ok will be a lie.

However, the above construction is optimal only if you need to perform an action in the default branch. Those. do something when there are no messages. There is a simpler and more understandable design.

 for val := range someChan { // получено сообщение } // канал закрыт 

In this case, the channel is read using for-range . When the channel is closed and the last message is read from it, the loop will exit.

Record

Writing to a closed channel causes panic. The current schema is incorrect. It is required to add some more synchronization primitive, so that there would be no recording to the closed channel. Here is an example at play.golang.org . And the case-default construction will not help here.

Actually the answer to the question. In this case, no way.

Explanation.

The design of the application should be such that the party creating the channel, closes it and writes the same to it. Moreover, in these cases it is recommended that the function return a read-only channel.

 func run () <-chan string { c := make(chan string) // [...] } 

In this case, the error will be visible at the compilation stage (example: play.golang.org ).

recover ()

Of course, you can call recover() in a deferred call to suppress panic. But this is fundamentally wrong. For this reason, I do not give an example.

  • With reading from the channels, everything is clear and you can find a lot of examples on this topic. Therefore it is the channels used for recording that are of interest. The question is where control passes to go-routone (lines 12-25) after the channel is closed? - chernomyrdin
  • @chernomyrdin, updated - Ivan Black