I’m trying to wrap my head around using Julia with some dynamic threading. Ability to handle externally-launched threads was introduced in 1.9 with jl_adopt_thread(). The main documentation seems limited to the release notes and the PR. There’re also third-party guides available, like this one
I am hitting a deadlock when joining external threads, and the workaround recommended in the guide above is to use jl_enter_threaded_region()
/jl_exit_threaded_region()
. I found this issue where a similar workaround is recommended, but not much explanation apart from “Don’t write buggy blocking loops, and you won’t have this bug”, which I’m not sure applies here.
function thread_create(f)
wrapped = _ -> (f(); nothing)
# NOTE: @cfunction also makes sure jl_adopt_thread() is called
wrapped_c = @cfunction($wrapped, Cvoid, (Ptr{Nothing},))
# without jl_enter_threaded_region/jl_exit_threaded_region, call to pthread_join/uv_thread_join() might deadlock
# @ccall jl_enter_threaded_region()::Cvoid
threadid = UInt[0]
err = @ccall uv_thread_create(threadid::Ptr{UInt}, wrapped_c::Ptr{Cvoid}, C_NULL::Ptr{Cvoid})::Cint
@assert err == 0
threadid[1]
end
function thread_join(threadid)
tid = UInt[threadid]
# I thought it may be GC-related deadlock, but gc_safe mode doesn't help
# gc_state = @ccall jl_gc_safe_enter()::Int8
err = @ccall uv_thread_join(tid::Ptr{UInt})::Cint
# @ccall jl_gc_safe_leave(gc_state::Int8)::Cvoid
@assert err == 0
# @ccall jl_exit_threaded_region()::Cvoid
nothing
end
threadid = thread_create() do
# some IO/sleep() here is required to trigger deadlock
println("Hello from Julia")
end
thread_join(threadid)
I write it here inline, but of course any number of layers of indirection could trigger the same problem.
So my questions are:
- is this indeed the right solution in my case? Am I using
jl_adopt_thread()
correctly? Is this something I can count on in the future? - would we all be better off doing it from
jl_adopt_thread()
or even switching to this mode entirely? What’s the downside? - if Julia de-facto already supports dynamically-created threads, why not include it in official Threads.jl API’s?