v icon indicating copy to clipboard operation
v copied to clipboard

can read from a closed channel

Open kbkpbot opened this issue 5 months ago • 5 comments

Describe the bug

After a channel was closed, following read can read from the closed channel.

Reproduction Steps

cc.v

module main

fn main() {
        ch := chan int{cap: 10}
        mut received := []int{}

        ch <- 1
        ch.close()    // close channel here
        mut done := false
        for !done {
                select {
                        val := <-ch {
                                // should not be here
                                dump('received ch')
                                received << val
                        }
                        else {
                                // channel closed
                                dump('closed')
                                done = true
                        }
                }
        }

        dump(received)
}

Expected Behavior

$ ./cc
[cc.v:19] 'closed': closed
[cc.v:25] received: []

Current Behavior

$ ./cc
[cc.v:14] 'received ch': received ch
^C

Possible Solution

No response

Additional Information/Context

No response

V version

V 0.4.10 566d22ab66b14655f1b1f2f4aa8396264ebf0c26

Environment details (OS name and version, etc.)

V full version V 0.4.10 566d22ab66b14655f1b1f2f4aa8396264ebf0c26
OS linux, Ubuntu 24.04.2 LTS
Processor 8 cpus, 64bit, little endian, Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz
Memory 7.54GB/15.51GB
V executable /media/HD/github/kbkpbot/v/v
V last modified time 2025-06-02 00:07:12
V home dir OK, value: /media/HD/github/kbkpbot/v
VMODULES OK, value: /home/mars/.vmodules
VTMP OK, value: /tmp/v_1000
Current working dir OK, value: /home/mars/v/bug/channel
Git version git version 2.43.0
V git status weekly.2025.17-228-g8f1bf53f-dirty
.git/config present true
cc version cc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
gcc version gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
clang version Ubuntu clang version 18.1.3 (1ubuntu1)
tcc version tcc version 0.9.28rc 2025-02-13 HEAD@f8bd136d (x86_64 Linux)
tcc git status thirdparty-linux-amd64 696c1d84
emcc version N/A
glibc version ldd (Ubuntu GLIBC 2.39-0ubuntu8.4) 2.39

[!NOTE] You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote. Other reactions and those to comments will not be taken into account.

kbkpbot avatar Jun 09 '25 13:06 kbkpbot

Connected to Huly®: V_0.6-23036

huly-for-github[bot] avatar Jun 09 '25 13:06 huly-for-github[bot]

I don't know if is useful a channel in a single thread, but seems next complete select form mentioned in the docs, registers the whole history channel had:

fn main() {
    ch := chan int{cap: 10}
    mut received := []int{}
    ch <- 1
    ch <- 2
    ch.close()
    mut done := false
    for !done {
        if select {
            val := <-ch {
                received << val
                println('received: ${received}')
            }
        } {
            println('not closed yet')
        } else {
            println('closed')
            done = true
        }
    }
}
received: [1]
not closed yet
received: [1, 2]
not closed yet
closed

jorgeluismireles avatar Jun 09 '25 16:06 jorgeluismireles

close channel in another thread, also has this problem:

module main

fn main() {
        ch := chan int{cap: 10}
        block := chan bool{}
        mut received := []int{}

        spawn fn [block, ch] () {
                ch <- 1
                ch.close()
                block <- true
        }()

        _ := <-block

        mut done := false
        for !done {
                select {
                        val := <-ch {
                                // should not be here
                                dump('received ch')
                                received << val
                        }
                        else {
                                // channel closed
                                dump('channel closed')
                                done = true
                        }
                }
        }

        dump(received)
}
$ ./ccc
[ccc.v:21] 'received ch': received ch
^C

kbkpbot avatar Jun 09 '25 23:06 kbkpbot

how about go handle this?

kbkpbot avatar Jun 09 '25 23:06 kbkpbot

In go this fails (with close or defaul is the same):

func main() {
	c := make(chan int)
	c <- 43
	//close(c)	
	for {
		select {
			case i := <- c:
				fmt.Println(i)
			//default:
			//	println("?")
		}
	}
}
fatal error: all goroutines are asleep - deadlock!

You need more code to communicate:

func read(c chan int, s chan bool) {
	i := <- c
	fmt.Println(i)
	s<- true
}

func write(c chan int) {
	time.Sleep(1 * time.Second)
	c <- 43
	close(c)
}

func main() {
	c := make(chan int)
	s := make(chan bool)
	go read(c, s)
	go write(c)
	<-s
}
43

jorgeluismireles avatar Jun 10 '25 00:06 jorgeluismireles