Skip to content

Commit dc57caf

Browse files
document isopen(::Channel) (#56376)
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]>
1 parent 671e1d8 commit dc57caf

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

base/channels.jl

+45-5
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,51 @@ function close(c::Channel, @nospecialize(excp::Exception))
212212
nothing
213213
end
214214

215-
# Use acquire here to pair with release store in `close`, so that subsequent `isready` calls
216-
# are forced to see `isready == true` if they see `isopen == false`. This means users must
217-
# call `isopen` before `isready` if you are using the race-y APIs (or call `iterate`, which
218-
# does this right for you).
219-
isopen(c::Channel) = ((@atomic :acquire c.state) === :open)
215+
"""
216+
isopen(c::Channel)
217+
Determines whether a [`Channel`](@ref) is open for new [`put!`](@ref) operations.
218+
Notice that a `Channel`` can be closed and still have
219+
buffered elements which can be consumed with [`take!`](@ref).
220+
221+
# Examples
222+
223+
Buffered channel with task:
224+
```jldoctest
225+
julia> c = Channel(ch -> put!(ch, 1), 1);
226+
227+
julia> isopen(c) # The channel is closed to new `put!`s
228+
false
229+
230+
julia> isready(c) # The channel is closed but still contains elements
231+
true
232+
233+
julia> take!(c)
234+
1
235+
236+
julia> isready(c)
237+
false
238+
```
239+
240+
Unbuffered channel:
241+
```jldoctest
242+
julia> c = Channel{Int}();
243+
244+
julia> isopen(c)
245+
true
246+
247+
julia> close(c)
248+
249+
julia> isopen(c)
250+
false
251+
```
252+
"""
253+
function isopen(c::Channel)
254+
# Use acquire here to pair with release store in `close`, so that subsequent `isready` calls
255+
# are forced to see `isready == true` if they see `isopen == false`. This means users must
256+
# call `isopen` before `isready` if you are using the race-y APIs (or call `iterate`, which
257+
# does this right for you).
258+
return ((@atomic :acquire c.state) === :open)
259+
end
220260

221261
"""
222262
empty!(c::Channel)

doc/src/base/parallel.md

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Base.put!(::Channel, ::Any)
6767
Base.take!(::Channel)
6868
Base.isfull(::Channel)
6969
Base.isready(::Channel)
70+
Base.isopen(::Channel)
7071
Base.fetch(::Channel)
7172
Base.close(::Channel)
7273
Base.bind(c::Channel, task::Task)

0 commit comments

Comments
 (0)