Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime: select should ignore closed channels #11344

Closed
nigeltao opened this issue Jun 23, 2015 · 6 comments
Closed

runtime: select should ignore closed channels #11344

nigeltao opened this issue Jun 23, 2015 · 6 comments
Milestone

Comments

@nigeltao
Copy link
Contributor

This program panics:

package main

import (
    "fmt"
)

func main() {
    c := make(chan int, 10)
    close(c)
    d := make(chan int, 10)
    for i := 0; i < 10; i++ {
        fmt.Println(i)
        select {
        case c <- 0:
        case d <- 0:
        }
    }
    fmt.Println("OK")
}

because c is still selectable even when closed. This seems consistent with the spec, but I think that the spec and the runtime should change.

@nigeltao nigeltao assigned nigeltao and robpike and unassigned nigeltao Jun 23, 2015
@nigeltao nigeltao added this to the Go1.6 milestone Jun 23, 2015
@bradfitz
Copy link
Contributor

Proposal process?

@nigeltao
Copy link
Contributor Author

Yeah probably, but I'll wait until the tree opens for 1.6. In the meantime, I wanted to write this down before I forgot, so I filed an old-fashioned issue.

@adg
Copy link
Contributor

adg commented Jun 24, 2015

There's not much of an argument here, so I suppose it's no surprise that I'm not convinced.

Select ignores cases that contain sends or recevies on a nil channel, which is consistent with just a stand-alone send or receive on a nil channel (outside the context of a select) blocking indefinitely.

If stand-alone sends to closed channels should panic, then they should panic in select too.

@bradfitz
Copy link
Contributor

Also need to consider whether this would be abused by people writing (or encouraging people to write) racy code, where it's unclear which goroutine is the closer.

@rsc
Copy link
Contributor

rsc commented Jul 2, 2015

Closing the channel is a send-like communication from the senders to the receivers that there will be no more sends. If a sender later tries to send on the channel, then the goroutine who did the close is clearly confused. That merits a panic, whether it is part of a select or an ordinary operation.

The fact that close is (like ordinary sends) a communication from sender to receiver is fundamental to its operation. It comes up repeatedly that people want to use close as a reverse signal from receivers to senders to say "stop sending to me". That is not what it means. It would break the unidirectionality of channels. And at least nine times out of ten the people who want to do this have not completely thought through the implications of this kind of cancellation mechanism. There almost always need to be two steps in a cancellation: a request for the cancellation and an acknowledgement that work has in fact stopped. Close can serve as the latter; it cannot serve as both, and we make it as hard as possible for people to do that accidentally.

This insistence that close is a sender -> receiver communication and not the reverse is also the reason why you cannot close a receive-only channel.

The issue report seems to suggest making an exception to the panic only for select, not for ordinary sends. In the run up to Go 1, we actively worked to make select { case X: } as close to plain 'X' as possible, for all communication operations X. I would not break that lightly. (The only exception involves order of evaluation in case Y = <-Z; in select, the evaluation of Z happens first. See http://play.golang.org/p/HppmwsO0QO)

Anyway, those are the reasons for why Go is what it is today. What are the reasons for changing it? They are conspicuously missing from the initial issue report.

@nigeltao
Copy link
Contributor Author

nigeltao commented Jul 2, 2015

Yeah, the more I think about it, the more the current behavior seems correct.

As for the motivation, I had a stream of events (a chan event), from a source that can eventually close the channel. Separately, I want to occasionally inject other events into that channel, without panic'ing with a send-on-close. I was hoping to do that via select, but I'll figure out another way instead.

@nigeltao nigeltao closed this as completed Jul 2, 2015
@golang golang locked and limited conversation to collaborators Jul 1, 2016
@rsc rsc unassigned robpike Jun 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants