Skip to content
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

Threads.@threads should not allow closures that contain a Core.Box. #57181

Closed
MasonProtter opened this issue Jan 28, 2025 · 3 comments
Closed
Labels
multithreading Base.Threads and related functionality

Comments

@MasonProtter
Copy link
Contributor

MasonProtter commented Jan 28, 2025

(Same issue as JuliaFolds2/OhMyThreads.jl#133)

Any time a user references an outer-local-variable inside a @threads block, they are creating a silent race condition, because inside the @threads block, accesses/re-assignments to that variable are simply reading/mutating a Core.Box.

Minimal demo:

let A = 1 #<------- some inoccuous unrelated definition
    
    res1 = zeros(Int, 10)
    res2 = zeros(Int, 10)
 
    # The wrong version
    Threads.@threads for i  eachindex(res1)
        A = i # <--- A coincidental name clash
        sleep(rand())
        res1[i] = A
    end

    # The right version
    Threads.@threads for i  eachindex(res2)
        local A = i # <--- Name clash avoided with local
        sleep(rand())
        res2[i] = A
    end

    @info "A very confusing result" res1' res2'
end

gives

┌ Info: A very confusing result
│   res1' =1×10 adjoint(::Vector{Int64}) with eltype Int64:8  6  10  6  2  6  4  8  10  4
│   res2' =1×10 adjoint(::Vector{Int64}) with eltype Int64:1  2  3  4  5  6  7  8  9  10

I'm pretty sure it's always a race condition to pass a closure with a Core.Box in it to Threads.@threads, even if in many cases the race condition is highly improbable to hit, therefore I think it'd actually be beneficial if we turned the res1 loop into an unconditional error.

This is especially important for @threads because it's not clear to the user that it creates a closure. A recent example in the wild of a user hitting this issue can be found here: https://discourse.julialang.org/t/why-does-julia-threads-in-the-following-way/124953

@MasonProtter MasonProtter added the multithreading Base.Threads and related functionality label Jan 28, 2025
@KristofferC
Copy link
Member

Dup of #14948?

@MasonProtter
Copy link
Contributor Author

Ah yes, I forgot that issue existed. This is the same problem, but I am suggesting here that we unconditionally error in this case, whereas the discussion there appears to have focused on "can the compiler fix this for me?" which never happened.

If you prefer, I can close this issue and move my comment there.

@KristofferC
Copy link
Member

Since it is the same issue perhaps it is best to keep the discussion there and not have one issue for every possible remedy of it.

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

No branches or pull requests

2 participants