Inconsistent results when using Threads.@threads in a loop

Disclaimer: I am not an expert in Threads.@threads or friends.

Applying any of the changes below makes it work correctly on v1.9.1:

  • add a local in front of v_re, v_im inside the loop body
  • rename v_re, v_im inside the loop body
  • rename or remove v_re, v_im outside the loop

Someone correct me, but this smells like a bug in Threads.@threads.
EDIT: As clarified in the comments below, this is intended but also bad behavior. What is happening is that by the current scoping rules, using the names v_re, v_im also after the loop body makes them being shared between threads, which causes a data race.


Here is the fixed version:

function coefs_w_threads(N)
    v = zeros(ComplexF64, N)
    Threads.@threads for k in 1:N-1
        local v_re = 0.5*k
        local v_im = -0.5*k
        v[k+1] = v_re + 1im*v_im
    end
    v_re = 0.25
    v_im = -0.25
    v[1] = v_re + 1im*v_im
    return v
end

function coefs(N)
    v = zeros(ComplexF64, N)
    for k in 1:N-1
        v_re = 0.5*k
        v_im = -0.5*k
        v[k+1] = v_re + 1im*v_im
    end
    v_re = 0.25
    v_im = -0.25
    v[1] = v_re + 1im*v_im
    return v
end

ref = coefs(1000)
threads = coefs_w_threads(1000)
# display(sum(ref) == sum(threads))
display(all(ref .== threads)) # more reliable test

EDIT: I had added the local to the coefs version instead of coefs_w_threads

5 Likes