After the channel is written, the channel must be closed, or there will be a deadlock in range traversal.

After the

channel is written, the channel must be closed, otherwise there will be a deadlock in range traversal. Is this correct?

so what if I have a scenario in which one goroutine writes data to the channel and one or more goroutine reads data from the channel without closing the channel?

< hr >

add:

my question is a little unclear. Writing to the channel is an endless cycle of continuous writing, and reading is also constant reading, so how do you close the channel? At present, I open a goroutine to continue to write, open 5 goroutine to read with range, there is no problem, but there is such a sentence in reading, so ask.

clipboard.png

this channel is constantly writing data, so there is no "channel after writing", so it cannot be closed, so the other goroutine can just read the data by range. , the question is changed to this, do you understand it correctly? at present, the program has not been reported wrong, just ask if it is standardized to write in this way.

Go
May.31,2022

After the
channel is written, the channel must be closed, otherwise a deadlock will occur in range traversal. Is this correct?

Yes, closing channel will cause for range to exit the loop.

however, it is dangerous to control read and write routine by simply turning off channel, because writing to a closed channel will crash directly.
so you have to add a status value to channel to prevent this from happening. Of course, you can also implement it with locks instead of channel.

here are two examples: the production / consumption model implemented with channel and without channel.
Note: the examples only provide ideas and are not perfect.

use channel

package main

import (
    "sync"
)

type Store struct {
    sync.Mutex // \ channel 
    ch         chan int
}

func NewStore() *Store {
    return &Store{ch: make(chan int, 128)}
}

func (store *Store) Read() int {
    return <-store.ch
}

func (store *Store) Write(value int) {
    store.Lock()
    defer store.Unlock()
    store.ch <- value
}

func (store *Store) Close() {
    store.Lock()
    defer store.Unlock()
    close(store.ch)
}

No channel

package main

import (
    "sync"
)

type Store2 struct {
    sync.Mutex
    link   []int
    closed bool
}

func (store *Store2) Read() int {
    store.Lock()
    defer store.Unlock()
    if len(store.link) == 0 {
        return -1
    }
    value := store.link[0]
    store.link = store.link[1:]
    return value
}

func (store *Store2) Write(value int) {
    store.Lock()
    defer store.Unlock()
    if !store.closed {
        store.link = append(store.link, value)
    }
}

func (store *Store2) Close() {
    store.Lock()
    defer store.Unlock()
    store.closed = true
}

if you have a definite number of writes, you can close after you finish it, and then read it with for range.

if you are indeterminate in the number of writes, you cannot close. Without close, you can't use for range, you can only read for {} in an endless loop (similar to message queue, anyway, I'll read as much as you write).

of course, even if it's an endless loop, it's best to have an end condition. For example, using select+ to control timeout


first of all, it is recommended to read and write more introductory materials, systematic learning, read a lot of code, and then write a lot of verification / Demo/ trial and error code, there will be no such questions.

< H1 > question < / H1 >
  1. After the

    channel is written, the channel must be closed, otherwise there will be a deadlock in range traversal. Is this correct?
    1) the channel must be closed after it is used, because in a long-running program, not closing the channel is a resource leak.
    2) otherwise, there will be a deadlock in the range traversal: it's not necessarily a deadlock, it's just that the goroutine where you're running range doesn't quit.

    for example, deadlock:

    
    

    for range:

        ch := make(chan int)
        go func(varch chan<- int) {
            //defer close(ch)
            //for i := 0; i < 100; iPP {
            //    ch <- i
            //}
            for i:=1;;iPP{
                varch <- i
                time.Sleep(time.Second)
            }
        }(ch)
    
        for x := range ch {
            fmt.Println(x)
        }
Menu