The @threads seems not working well with async channel. the following code blocks forever, is there something wrong?
using Base.Threads
c = Channel{Int}(1)
mutex = SpinLock()
@sync begin
@async begin
# for i in 1:10
@threads for i in 1:10
lock(mutex)
push!(c, i)
unlock(mutex)
end
end
@async begin
while true
lock(mutex)
i = take!(c)
unlock(mutex)
println(i)
end
end
end
close(c)
Not answering your question, but I am curious if lock / unlock pattern is common, would a @locked macro like this be useful?
julia> using Base.Threads: lock, unlock
julia> macro locked(mutex, block)
quote
lock($mutex)
value = $block
unlock($mutex)
value
end |> esc
end
@locked (macro with 1 method)
julia> using Base.Threads: SpinLock, @threads
julia> c = Channel{Int}(1)
Channel{Int64}(sz_max:1,sz_curr:0)
julia> m = SpinLock()
Base.Threads.TatasLock(Base.Threads.Atomic{Int64}(0))
julia> @threads for i in 1:10
@locked m begin
push!(c, i)
take!(c) |> println
end
end
1
2
3
4
5
6
7
8
9
10
julia> close(c)
I think this is deadlocking, is there a way to check if a mutex is locked?
@async blocks are managed with Tasks. So are Channels. Tasks are currently implemented through the event-loop infrastructure of libuv, which is not thread-safe. Perhaps one of the developers can explain this strange design decision.
Even without threads, I think you need more logic, probably with an explicit yield, to avoid deadlock.