# Compare and swap operation on mmap/shared-memory

**URL:** https://discourse.julialang.org/t/compare-and-swap-operation-on-mmap-shared-memory/93425
**Category:** General Usage
**Created:** [January 23, 2023, 8:11pm UTC](https://discourse.julialang.org/t/compare-and-swap-operation-on-mmap-shared-memory/93425 "2023-01-23T20:11:13Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![Impressium](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/impressium/32/19575_2.png) [@Impressium](https://discourse.julialang.org/u/Impressium)
#### Post date: [January 23, 2023, 8:11pm UTC](https://discourse.julialang.org/t/compare-and-swap-operation-on-mmap-shared-memory/93425/1 "2023-01-23T20:11:13Z")

</div>

Hi all 🙂

How can I do an `cas` (compare and swap operation) on memory mapped arrays in Julia.

```julia
julia> v = SharedArray{UInt8}(abspath("test.bytes"), (1000,));

julia> using SharedArrays

julia> v = SharedArray{UInt8}(abspath("test.bytes"), (1000,));

julia> if v[1] == 0x01 # I wanna do this atomically - atomic_cas!
           v[1] = 0x00
       end

```

Thanks

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [January 24, 2023, 12:05pm UTC](https://discourse.julialang.org/t/compare-and-swap-operation-on-mmap-shared-memory/93425/2 "2023-01-24T12:05:57Z")

</div>

For some reason atomics.jl decides against exporting that functionality. You can get it by copy-pasting and adjusting the code for `Threads.atomic_cas!`, like e.g.

```julia
my_atomic_cas!(ptr::Ptr{Int64}, cmp::Int64, new::Int64) = Core.Intrinsics.llvmcall("""
                            %ptr = inttoptr i64 %0 to i64*
                            %rs = cmpxchg i64* %ptr, i64 %1, i64 %2 acq_rel acquire
                            %rv = extractvalue { i64, i1 } %rs, 0
                            ret i64 %rv
                            """, Int64, Tuple{Ptr{Int64},Int64,Int64},
                            ptr, cmp, new)

```

Then you can use that via e.g. `my_atomic_cas!(pointer(a,2), 3, 4)` (you may need to take care to sprinkle `GC.@preserve` at appropriate positions).

Does anyone know why we don’t export atomic operations on pointers and array elements?

---

<div class="post-metadata">

### Author: ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)
#### Post date: [January 25, 2023, 4:36am UTC](https://discourse.julialang.org/t/compare-and-swap-operation-on-mmap-shared-memory/93425/3 "2023-01-25T04:36:28Z")

</div>

We do. It is still in Core.Intrinsics though, since we have not finalized a Base API yet

---

<div class="post-metadata">

### Author: ![Impressium](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/impressium/32/19575_2.png) [@Impressium](https://discourse.julialang.org/u/Impressium)
#### Post date: [January 26, 2023, 12:51pm UTC](https://discourse.julialang.org/t/compare-and-swap-operation-on-mmap-shared-memory/93425/4 "2023-01-26T12:51:31Z")

</div>

I just edited the post to make it more clear. Is your llvm code valid for the this?

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [January 27, 2023, 1:10pm UTC](https://discourse.julialang.org/t/compare-and-swap-operation-on-mmap-shared-memory/93425/5 "2023-01-27T13:10:34Z")

</div>

I think your example wants to be

```julia
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:

```julia
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](https://github.com/JuliaLang/julia/blob/81813164963f38dcd779d65ecd222fad8d7ed437/doc/src/base/multi-threading.md)

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?

---

<div class="post-metadata">

### Author: ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)
#### Post date: [January 27, 2023, 3:06pm UTC](https://discourse.julialang.org/t/compare-and-swap-operation-on-mmap-shared-memory/93425/6 "2023-01-27T15:06:31Z")

</div>

@Impressium We don’t currently support arrays (or sharedarray) with a high level API. Mainly because atomics on arrays are pretty slow, so there is often a better performing implementation with locks possible. We will likely add it at some point, however, since it does have its uses anyways. Currently, there is an experimental package though for experimenting with it: [https://juliaconcurrent.github.io/Atomix.jl/dev/](https://juliaconcurrent.github.io/Atomix.jl/dev/)

> instead of the obvious and almost verbatim requested

The standard memory models for CPUs (e.g. in use by C11) declare it to be undefined behavior to cast a non-atomic field pointer for use with atomics. The standards authors demonstrated that it lead to mis-compilations and incorrect execution, which is not something that Julia wants to accidentally expose to users.

> `llvmcall` is more stable than manually

llvmcall IR frequently changes meaning between LLVM releases. It is explicitly not stable, per llvm’s policies. In contrast, Core.Intrinsics are part of the Julia API. As you mentioned, there are also a variety of correctness improvements possibly by using intrinsics which not expressible in a naked llvmcall. With enough annotations, the user can recover most of the correctness, and convert them into simple inefficiencies instead. But since intrinsics express the actual user intent, they do not suffer from those deficiencies.

---

<div class="post-metadata">

### Author: ![Impressium](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/impressium/32/19575_2.png) [@Impressium](https://discourse.julialang.org/u/Impressium)
#### Post date: [January 30, 2023, 9:56am UTC](https://discourse.julialang.org/t/compare-and-swap-operation-on-mmap-shared-memory/93425/7 "2023-01-30T09:56:40Z")

</div>

Thank you all 🙂

@jameson  
To clarify what I want (don’t know if it’s the right way or even possible this why): I wanna use the shared-array within two separate processes. The `cas` on the array/file is used to lock it via a flag for the other process. Is that possible this way and does atomic operation in shared-array work like that?

---

<div class="post-metadata">

### Author: ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)
#### Post date: [January 30, 2023, 4:13pm UTC](https://discourse.julialang.org/t/compare-and-swap-operation-on-mmap-shared-memory/93425/8 "2023-01-30T16:13:05Z")

</div>

You probably just want a `mmap` pointer (from the Mmap) package, since the array functionality is not desirable in that case. You can use that to get memory for a normal pthread\_mutex and configure it with `pthread_mutexattr_setpshared` to be `PTHREAD_PROCESS_SHARED`. The equivalent on Windows is [CreateMutex](https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createmutexa).
