Skip to content

Channels throw exception when filled and read from tasks on different threads (sticky = false) #32575

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

Closed
NHDaly opened this issue Jul 13, 2019 · 2 comments · Fixed by #32584
Closed
Assignees
Labels
bug Indicates an unexpected problem or unintended behavior multithreading Base.Threads and related functionality

Comments

@NHDaly
Copy link
Member

NHDaly commented Jul 13, 2019

I'm opening this PR after some conversation on Slack about using Channels with the new PART multithreaded task runtime. Sorry it took me so long to open this, @JeffBezanson.

The Channel functions sometimes throw an exception when reading values off a channel: cannot switch to task running on another thread

(I read #30186, which looks like it should have added multithreading support for Channels. So it's also possible that I'm actually just not using them correctly?)

Here is an example that seems to (sometimes) trigger the exception:

julia> using Test;

julia> begin
           ch = Channel{Char}(0)
           t = Task(()->for v in "hello" put!(ch, v) end)
           t.sticky = false
           bind(ch, t)
           schedule(t)
           @test String(collect(c)) == "hello"
       end
Error During Test at none:7
  Test threw exception
  Expression: String(collect(c)) == "hello"
  cannot switch to task running on another thread
  Stacktrace:
   [1] check_channel_state at /Users/nathan.daly/src/julia/base/channels.jl:147 [inlined]
   [2] take_unbuffered(::Channel{Char}) at /Users/nathan.daly/src/julia/base/channels.jl:396
   [3] take! at /Users/nathan.daly/src/julia/base/channels.jl:374 [inlined]
   [4] iterate(::Channel{Char}, ::Nothing) at /Users/nathan.daly/src/julia/base/channels.jl:440
   [5] iterate at /Users/nathan.daly/src/julia/base/channels.jl:439 [inlined]
   [6] _collect(::UnitRange{Int64}, ::Channel{Char}, ::Base.HasEltype, ::Base.SizeUnknown) at ./array.jl:569
   [7] collect(::Channel{Char}) at ./array.jl:558
   [8] top-level scope at none:7
   [9] eval at ./boot.jl:330 [inlined]
   [10] repleval(::Module, ::Expr) at /Users/nathan.daly/.julia/packages/Atom/cR6bU/src/repl.jl:135
   [11] (::getfield(Atom, Symbol("##168#170")){Module})() at /Users/nathan.daly/.julia/packages/Atom/cR6bU/src/repl.jl:157
   [12] with_logstate(::getfield(Atom, Symbol("##168#170")){Module}, ::Base.CoreLogging.LogState) at ./logging.jl:395
   [13] with_logger at ./logging.jl:491 [inlined]
   [14] evalrepl(::Module, ::String) at /Users/nathan.daly/.julia/packages/Atom/cR6bU/src/repl.jl:148
   [15] top-level scope at /Users/nathan.daly/.julia/packages/Atom/cR6bU/src/repl.jl:190
   [16] eval(::Module, ::Any) at ./boot.jl:330
   [17] eval_user_input(::Any, ::REPL.REPLBackend) at /Users/nathan.daly/builds/julia-1.3/usr/share/julia/stdlib/v1.3/REPL/src/REPL.jl:86
   [18] macro expansion at /Users/nathan.daly/builds/julia-1.3/usr/share/julia/stdlib/v1.3/REPL/src/REPL.jl:118 [inlined]
   [19] (::getfield(REPL, Symbol("##26#27")){REPL.REPLBackend})() at ./task.jl:270
  
ERROR: There was an error during testing

That seems to fail about 1/5 times I run it.

@NHDaly
Copy link
Member Author

NHDaly commented Jul 13, 2019

Although, huh, weirdly, I seem to only see this happening in Atom. That fails pretty often in atom, maybe around half the time, but at the plain Julia REPL in the terminal, I haven't seen it fail yet. I don't know if Atom is doing something weird with tasks?

EDIT: Removed the rest of this post. I didn't realize that Atom was setting JULIA_NUM_THREADS=6 and the default is JULIA_NUM_THREADS=1. Of course this error only occurs when nthreads > 1.

Here is a reproduction at the terminal:

julia> versioninfo()
Julia Version 1.3.0-DEV.540
Commit faefe2ae64* (2019-07-13 08:34 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin18.6.0)
  CPU: Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)
Environment:
  JULIA_NUM_THREADS = 4

julia> begin
           ch = Channel{Char}(0)
           t = Task(()->for v in "hello" put!(ch, v) end)
           t.sticky = false
           bind(ch, t)
           schedule(t)
           String(collect(ch)) == "hello"
       end

ERROR: cannot switch to task running on another thread
Stacktrace:
 [1] check_channel_state at ./channels.jl:117 [inlined]
 [2] take_unbuffered(::Channel{Char}) at ./channels.jl:366
 [3] take! at ./channels.jl:344 [inlined]
 [4] iterate(::Channel{Char}, ::Nothing) at ./channels.jl:410
 [5] _collect(::UnitRange{Int64}, ::Channel{Char}, ::Base.HasEltype, ::Base.SizeUnknown) at ./array.jl:570
 [6] collect(::Channel{Char}) at ./array.jl:558
 [7] top-level scope at REPL[2]:7

@NHDaly
Copy link
Member Author

NHDaly commented Jul 16, 2019

Thanks Jeff!! 😊👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Indicates an unexpected problem or unintended behavior multithreading Base.Threads and related functionality
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants