Multithreading mystery

Is this a bug or am I misusing/misunderstanding @sync/@spawn?

julia> function f()
           x = 0
           @sync while x < 3
               @spawn println(x)
               x += 1
           end
       end
f (generic function with 1 method)

julia> f()
3
3
3

In Julia 1.4 you can use $ to copy the current value of x into the macro. I think you see this behavior because the outer while loop has already finish before the thread from Threads.@spawn starts. By than x=3 and gets printed.

function f()
   x = 0
   @sync while x < 3
      Threads.@spawn println($x)
      x += 1
   end
end
3 Likes

Note that at their core @spawn code and @async code are just syntax sugar of schedule(Task(() -> code)). So, normal caveats of closures apply. See:

julia> function f()
           x = 0
           funcs = []
           while x < 3
               push!(funcs, () -> println(x))
               x += 1
           end
           for g in funcs
               g()
           end
       end
f (generic function with 3 methods)

julia> f()
3
3
3
5 Likes

Thanks both. My takeaway is that @macroexpand is the key to understanding what’s going on and that much caution is required when using a variable inside @spawn that is defined outside @sync.

2 Likes