Incrementing AtomicMemory{SVector}

I’m trying to use the new `AtomicMemory in 1.11 to increment entries of a vector in an atomic way. However, the following example hangs:

using StaticArrays
mem = AtomicMemory{SVector{2,Float64}}(undef, 10)

# Initialize to zero
for j in eachindex(mem)
    Core.memoryrefset!(memoryref(mem, j), SVector(0.0, 0.0), :monotonic, true)
end

#Increment every element
for j in eachindex(mem)
    @show j
    Core.memoryrefmodify!(memoryref(mem, j), +, SVector(1.0, 1.0), :monotonic, true)
end

It prints out

j = 1
j = 2

but then hangs. It works fine when using a primitive type (Float64) instead of SVector, though. I suspect the +(SVector, SVector) operator is causing issues, but it’s hard to tell as Core.memoryrefmodify! doesn’t have much documentation…

1 Like

This appears to be a deadlock (which interestingly doesn’t seem to exist in 1.12 even though the code is basically the same).
Edit: it’s especially surprising that this deadlocks given the fact that there really doesn’t look like there should be any lock contention at all…

1 Like

1.12 uses a lock cmpxchg16b instruction, whereas 1.11 resorts to calls to jl_lock_field/jl_unlock_field. Perhaps it wasn’t quite finished yet?

1 Like

That part is just a result of increase max atomic size to 16 on 64-bit platforms by vtjnash · Pull Request #42268 · JuliaLang/julia · GitHub increasing our max atomic size. The issue still doesn’t reproduce for objects twice as big on 1.12 where we still use a lock:

mem = AtomicMemory{NTuple{4,Float64}}(undef, 10)
for j in eachindex(mem)
    @show j
    Core.memoryrefmodify!(memoryref(mem, j), (x,y)->x.+y, (1.0, 1.0, 1.0, 1.0), :monotonic, true)
end
1 Like