I think your example wants to be
if v[1] == 0x01 # I wanna do this atomically - atomic_cas!
v[1] = 0x00
end
i.e. if the array element is as expected, then replace it with a different value (and if it is unexpected, e.g. because somebody updated it concurrently, then fail and write nothing – your code will have a branch to handle it).
The thing you wrote (if v[1] != 0x00 v[1] = 0x00 end
) is rather weird and not CAS. You’d need to explain the desired effect of that and how that differs from plain v[1] = 0x00
(memory mapped IO? Avoid marking the page dirty?).
Otherwise you need to adjust the types from Int64 to UInt8 to use the example code I wrote:
my_atomic_cas!(ptr::Ptr{UInt8}, cmp::UInt8, new::UInt8) = Core.Intrinsics.llvmcall("""
%ptr = inttoptr i64 %0 to i8*
%rs = cmpxchg i8* %ptr, i8 %1, i8 %2 acq_rel acquire
%rv = extractvalue { i8, i1 } %rs, 0
ret i8 %rv
""", UInt8, Tuple{Ptr{UInt8},UInt8,UInt8},
ptr, cmp, new)
@jameson Thanks for referring me to julia/multi-threading.md at 81813164963f38dcd779d65ecd222fad8d7ed437 · JuliaLang/julia · GitHub
When trying to use the new fancy atomic things, I am somewhat stumped? For some reason replacefield!
does not support index exchanges on pointers/arrays; and even replacefield!(Ref(4), :x, 4, 5, :acquire_release) fails with
ERROR: ConcurrencyViolationError(“replacefield!: non-atomic field cannot be written atomically”)`? Why that instead of the obvious and almost verbatim requested LOCK CMPXCHG8b?
So, what is the official recommendation? I’d guess that llvmcall
is more stable than manually using a barely documented intrinsic? The main point I see for intrinsics as opposed to llvmcall is that the core team can put better aliasing info on the pointer than us mere end-users can access in llvmcall?