-
Notifications
You must be signed in to change notification settings - Fork 91
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
is_threading is racy #232
Comments
ah, true. It would be good to avoid a lock though, as the reason for this check is to avoid the need for a lock, given that locking got slower in recent julia versions |
Which use case are you most concerned about, performance-wise (that isn't covered by the nthreads() fast path)? I don't see an obvious way to avoid locking altogether, other than avoiding the lock by using a lock-free counter to track work altogether. Right now, I am personally only really interested in function is_threading()
Threads.nthreads() == 1 && return false
if Threads.threadid() > 1
# Called from another thread; so certainly in a @threads region.
return true
end
# On the main thread, so just check if we are in a @threads region.
return ccall(:jl_in_threaded_region, Cint, ()) != 0
end might do the trick. This wouldn't work for In my threaded programs, the progress meter instance is either going to be across threads anyway, or the situation will be such that the overhead from an uncontested lock is insignificant compared to the actual computation, though, so I'm not sure this problem needs to be solved. If it does, perhaps there could be an explicit thread safety flag/choice of variants (say, |
It's quite expensive to lock each iteration on tight loops. If a user has It may be over-optimization though. Redesign proposals would definitely be welcomed by me! |
I've honestly not used ProgressMeter.jl enough yet to be able to judge what the correct design tradeoffs are. One option to lower the overhead would be to use lock-free atomics instead, but then printing the updates could presumably only be done from the main thread to make sure the updates are ordered correctly. Using Threads.SpinLock might also be cheaper. |
Workaround for anyone else who might be concerned about this: p = Progress(n)
append!(p.threads_used, 1:Threads.nthreads())
# code using p
function is_threading(p::AbstractProgress)
Threads.nthreads() == 1 && return false
length(p.threads_used) > 1 && return true
return lock(lk) do
if !in(Threads.threadid(), p.threads_used)
push!(p.threads_used, Threads.threadid())
end
return length(p.threads_used) > 1
end
end
EDIT: scratch, that, it's not exceptional if |
Yeah on a I don't yet have a decent design to fix this. Further suggestions appreciated! |
Suggestion by @vchuravy
Also from @vtjnash
|
It happened in CI Stacktrace
|
The push! there looks very dangerous when used by multiple threads |
Just to mention that this issue is now breaking packages (one mine at least) in Julia 1.11. Thus, a safe fix for this is necessary asap. |
One alternative could be add a "no_lock" keyword argument, as an opt in, with the appropriate explanation. |
Sounds like a good quickfix |
I think this update is a reasonable one, which solves the issue with very minor modifications: #321 Relative to what is proposed in #232 (comment), what I do there is just define a new lock and just use the lock if the |
fixed by #322 |
In
is_threading
,p.threads_used
, aVector
of thread ids, is accessed and updated:ProgressMeter.jl/src/ProgressMeter.jl
Lines 463 to 470 in 5826a75
I don't think
Vector
is thread-safe, though – wouldn't accessesthreads_used
also need some form of locking?The text was updated successfully, but these errors were encountered: