-2

If I have multiple goroutines reading and writing to the same channel, are there any ways to close the channel at certain point, for example after a fix amount of elements are written.


func foo(c chan int) {
    for i := range c {
        // how to close the channel after 100 integers are written?
        c <- i + 1
        c <- i + 2
    }
}

func bar() {
    c := make(chan int, 200)
    c <- 0
    go foo(c)
    go foo(c)
    go foo(c)
}
puoklam
  • 25
  • 4
  • 2
    A channel may only be closed once. If you have multiple senders, you must coordinate them. See [Closing channel of unknown length](https://stackoverflow.com/questions/34283255/closing-channel-of-unknown-length/34283635#34283635) – icza Dec 29 '21 at 16:46
  • 3
    You normally would not want to be receiving and sending from the same channel in a goroutine like this, since it makes channel and data ownership hard to determine, and deadlocks are easy to create. What is the problem you are trying to solve? – JimB Dec 29 '21 at 16:46
  • Does this answer your question? [Closing channel of unknown length](https://stackoverflow.com/questions/34283255/closing-channel-of-unknown-length) – erik258 Dec 29 '21 at 17:26
  • @icza Waitgroup is useful when I know when the senders complete, but in this case the senders are inside a loop of channel receive, its hard to determine when to do a Done on waitgroup – puoklam Dec 30 '21 at 02:26
  • @JimB I'm trying to write a sha256 brute force program, each time receive a string from channel will sends n strings back, e.g. receiving "a", sending "aa", ..., "az" – puoklam Dec 30 '21 at 02:31

1 Answers1

0

Give conditional case would work for it:

for i := 0; i <= cap(c); i++ {
        // how to close the channel after 100 integers are written? 
        c <- i + 1
        // since you send 2 values to channel for each i loop, you need to half of it.
        if i == 49 { //if you asking why 49, you have sent one value on bar function. Also to make it perfectly 100 integer in total.
             close(ch)
             break // terminating the function after the closing channel, it will run in panic because the function still running and keep sending value on channel which was already closed.
        }
        c <- i + 2
}
Output :
0
1
2
2
3
3
...
50
50

Just give some information about channel, don't use range on channel if you havent sent anything on it... If you put "i range channel" before you have value on channel, it will not read anything.

Back to again to your code If you run this code :

func bar() {
    c := make(chan int, 200)
    c <- 0
    go foo(c)
    go foo(c) // run in panic
    go foo(c) // run in panic
}

It will run in panic, since the channel already closed which mean your channel not accepting any values again.

Take a look at this picture, let say you make a buffered channel with 3 capacity. And you going to close after receiving 2 values to send it will run in panic if you try to send values on it again. Here

  • what if I need multiple goroutines to handle the data? or should I avoid doing this? – puoklam Dec 30 '21 at 09:52
  • As long you know what you do, go for it. You need better understanding concurrency too, how they work... you can try to read literature book about it or any source. But go tour is already enought to understand how it work. So let your imagination come true on code xD – Panji Tri Wahyudi Dec 30 '21 at 10:01