Skip to content

Commit

Permalink
document isopen(::Channel) (JuliaLang#56376)
Browse files Browse the repository at this point in the history
This PR has two purposes -- 
1) Add some documentation for public API
2) Add a small note about a footgun I've hit a few times: `!isopen(ch)`
does not mean that you are "done" with the channel because buffered
channels can still have items left in them that need to be taken.

---------

Co-authored-by: CY Han <[email protected]>
  • Loading branch information
mrufsvold and inkydragon authored Nov 1, 2024
1 parent 671e1d8 commit dc57caf
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 5 deletions.
50 changes: 45 additions & 5 deletions base/channels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,51 @@ function close(c::Channel, @nospecialize(excp::Exception))
nothing
end

# Use acquire here to pair with release store in `close`, so that subsequent `isready` calls
# are forced to see `isready == true` if they see `isopen == false`. This means users must
# call `isopen` before `isready` if you are using the race-y APIs (or call `iterate`, which
# does this right for you).
isopen(c::Channel) = ((@atomic :acquire c.state) === :open)
"""
isopen(c::Channel)
Determines whether a [`Channel`](@ref) is open for new [`put!`](@ref) operations.
Notice that a `Channel`` can be closed and still have
buffered elements which can be consumed with [`take!`](@ref).
# Examples
Buffered channel with task:
```jldoctest
julia> c = Channel(ch -> put!(ch, 1), 1);
julia> isopen(c) # The channel is closed to new `put!`s
false
julia> isready(c) # The channel is closed but still contains elements
true
julia> take!(c)
1
julia> isready(c)
false
```
Unbuffered channel:
```jldoctest
julia> c = Channel{Int}();
julia> isopen(c)
true
julia> close(c)
julia> isopen(c)
false
```
"""
function isopen(c::Channel)
# Use acquire here to pair with release store in `close`, so that subsequent `isready` calls
# are forced to see `isready == true` if they see `isopen == false`. This means users must
# call `isopen` before `isready` if you are using the race-y APIs (or call `iterate`, which
# does this right for you).
return ((@atomic :acquire c.state) === :open)
end

"""
empty!(c::Channel)
Expand Down
1 change: 1 addition & 0 deletions doc/src/base/parallel.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Base.put!(::Channel, ::Any)
Base.take!(::Channel)
Base.isfull(::Channel)
Base.isready(::Channel)
Base.isopen(::Channel)
Base.fetch(::Channel)
Base.close(::Channel)
Base.bind(c::Channel, task::Task)
Expand Down

0 comments on commit dc57caf

Please sign in to comment.