# Store/load using shared memory for multithreade application

**URL:** <https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073>\
**Category:** Help\
**Tags:** memory-management\
**Created:** [January 31, 2024, 2:49pm UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073 "2024-01-31T14:49:38Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![jabolcni](https://ziggit.dev/user_avatar/ziggit.dev/jabolcni/32/1694_2.png) [@jabolcni](https://ziggit.dev/u/jabolcni)\
**Post date:** [January 31, 2024, 2:49pm UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/1 "2024-01-31T14:49:38Z")

</div>

I have a question regarding of storing and loading data from array from different threads. So basically how I can store/load using shared memory.

I have `ttArray: []u128`, where I store variables of type `scoreEntry` which is packed struct of size 128 bits

```zig
pub const scoreEntry = packed struct {
    hash_key: u64,
    move: Move, // 16-bits
    score: i32,
    bound: Bound, // 2-bits
    depth: u8,
    age: u6,
};

```

This is a structure that stores data about chess positions during search for best move. I plan to use multi-threaded search where I will run multiple search routines in separate threads and all threads with store or load data from global `ttArray`, which will act as shared memory. This approach is called Lazy SMP ([Lazy SMP - Chessprogramming wiki](https://www.chessprogramming.org/Lazy_SMP)).

As far as I was reading and studying I need to use `@atomicRmw` for storing and `@atomicLoad` for loading data, but I haven’t found good examples and I am not sure if this is correct approach.

---

<div class="post-metadata">

**Author:** ![dude\_the\_builder](https://ziggit.dev/user_avatar/ziggit.dev/dude_the_builder/32/557_2.png) [@dude\_the\_builder](https://ziggit.dev/u/dude_the_builder)\
**Post date:** [January 31, 2024, 2:55pm UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/2 "2024-01-31T14:55:46Z")

</div>

I think `std.atomic` provides a friendlier interface for atomic operations. For Zig master it’s [here](https://github.com/ziglang/zig/blob/master/lib/std/atomic.zig) and for 0.11 [here](https://github.com/ziglang/zig/blob/0.11.x/lib/std/atomic.zig). You basically wrap your data in an `Value` or `Atomic` and then you have `load` and `store` methods.

---

<div class="post-metadata">

**Author:** ![dude\_the\_builder](https://ziggit.dev/user_avatar/ziggit.dev/dude_the_builder/32/557_2.png) [@dude\_the\_builder](https://ziggit.dev/u/dude_the_builder)\
**Post date:** [January 31, 2024, 2:59pm UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/3 "2024-01-31T14:59:12Z")

</div>

You may also want to test the non-atomic way using a `std.Thread.Mutex`. I’ve found that depending on the situation atomics may be faster and in other cases the mutex is faster. You always have to test and see with multithreading.

---

<div class="post-metadata">

**Author:** ![mperillo](https://ziggit.dev/user_avatar/ziggit.dev/mperillo/32/1280_2.png) [@mperillo](https://ziggit.dev/u/mperillo)\
**Post date:** [January 31, 2024, 3:05pm UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/4 "2024-01-31T15:05:07Z")

</div>

> [@dude\_the\_builder](#):
>
> I think `std.atomic` provides a friendlier interface for atomic operations. For Zig master it’s [here](https://github.com/ziglang/zig/blob/master/lib/std/atomic.zig) and for 0.11 [here](https://github.com/ziglang/zig/blob/0.11.x/lib/std/atomic.zig). You basically wrap your data in an `Value` or `Atomic` and then you have `load` and `store` methods.

I don’t think using `std.Atomic` is the best solution in this case, since you need atomic access to an array element, not to the entire array.

---

<div class="post-metadata">

**Author:** ![LucasSantos91](https://ziggit.dev/user_avatar/ziggit.dev/lucassantos91/32/440_2.png) [@LucasSantos91](https://ziggit.dev/u/LucasSantos91)\
**Post date:** [January 31, 2024, 6:49pm UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/5 "2024-01-31T18:49:31Z")

</div>

It takes some effort to wrangle the compiler into doing what you want.

```zig
const std = @import("std");

pub const ScoreEntry = packed struct {
    hash_key: u64,
    move: u16,
    score: i32,
    bound: u2, 
    depth: u8,
    age: u6,
};

pub fn main() void{
  var a: ScoreEntry = undefined;
  const b: ScoreEntry = .{
    .hash_key = 0,
    .move = 1,
    .score = 2,
    .bound = 3,
    .depth = 4,
    .age = 5,
  };
  const dstPtr: *u128 = @ptrCast(&a);
  const srcPtr: *const u128 = @ptrCast(&b);

  @atomicStore(
  u128, 
  dstPtr, 
  srcPtr.*, 
  .Monotonic,
  );

  std.debug.print("{any}\n", .{a});
}

```

[Godbolt](https://godbolt.org/z/cxGWzYf3Y)

> [@mperillo](#):
>
> since you need atomic access to an array element, not to the entire array.

There is no such thing as “atomic access to the entire array”. Atomic is about operations, not types. You operate atomically on an element. There is no way to operate atomically on an array, unless you can pack the entire array into a register. std.atomic is just a very thin wrapper over the `@atomic*` builtins. In this case, the atomic approach doesn’t work because `@atomic*` doesn’t operate on structs, hence the casts I used above.

---

<div class="post-metadata">

**Author:** ![AndrewCodeDev](https://ziggit.dev/letter_avatar_proxy/v4/letter/a/278dde/32.png) [@AndrewCodeDev](https://ziggit.dev/u/AndrewCodeDev)\
**Post date:** [January 31, 2024, 10:20pm UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/6 "2024-01-31T22:20:06Z")

</div>

> [@LucasSantos91](#):
>
> There is no such thing as “atomic access to the entire array”.

Yeah, at that point you’re crossing into mutex territory. Now, if you wanted an array of atomic values, that’s another issue. Or, if you wanted to build a kind of ticket-mutex that uses an atomic counter to track whose turn it is… then we’re getting into atomics being useful.

@jabolcni If you just want to lock down a resource, you probably want a mutex. I’d start with that first and see where your bottlenecks are. At the very least, it’s super easy to implement an example to get some baselines for further experiments.

---

<div class="post-metadata">

**Author:** ![jabolcni](https://ziggit.dev/user_avatar/ziggit.dev/jabolcni/32/1694_2.png) [@jabolcni](https://ziggit.dev/u/jabolcni)\
**Post date:** [February 1, 2024, 7:21am UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/7 "2024-02-01T07:21:27Z")

</div>

So I arrived to something like this

```zig
    inline fn store_atomic(self: *TranspositionTable, entry: scoreEntry, indx: u64) void {
        @atomicStore(u128, &self.ttArray[indx], @as(*const u128, @ptrCast(&entry)).*, .SeqCst);
    }

```

```zig
    inline fn load_atomic(self: *TranspositionTable, indx: u64) scoreEntry {
        var raw = @atomicLoad(u128, &self.ttArray[indx], .SeqCst);
        return @as(*scoreEntry, @ptrCast(&raw)).*;
    }

```

```zig
    inline fn load_simple(self: *TranspositionTable, indx: u64) scoreEntry {
        return @as(*scoreEntry, @as(*scoreEntry, @ptrCast(&self.ttArray[indx]))).*;
    }

```

Pointer casts are trial and error, this seems to work, but using `@atomicLoad` is slower than just using `load_simple`. I am not sure which type of `order` I should use, I read about them all, but this is the first time that I am using anything atomic, so I do not have any experiences. I also need to test this on linux.

I will also try to figure out mutex-es, so that I can test differences.

---

<div class="post-metadata">

**Author:** ![IntegratedQuantum](https://ziggit.dev/user_avatar/ziggit.dev/integratedquantum/32/782_2.png) [@IntegratedQuantum](https://ziggit.dev/u/IntegratedQuantum)\
**Post date:** [February 1, 2024, 9:39am UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/8 "2024-02-01T09:39:43Z")

</div>

Another question you should ask yourself is if you really need sequential consistency. There are many weaker(→faster) versions of atomicity which might be enough here.  
You can check out the llvm guide for help, it’s a bit technical, but it gives you a description what each of the atomic orders do: [https://llvm.org/docs/Atomics.html#id7](https://llvm.org/docs/Atomics.html#id7)

---

<div class="post-metadata">

**Author:** ![jabolcni](https://ziggit.dev/user_avatar/ziggit.dev/jabolcni/32/1694_2.png) [@jabolcni](https://ziggit.dev/u/jabolcni)\
**Post date:** [February 1, 2024, 11:01am UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/9 "2024-02-01T11:01:13Z")

</div>

> [@IntegratedQuantum](#):
>
> Another question you should ask yourself is if you really need sequential consistency. There are many weaker(→faster) versions of atomicity which might be enough here.

Actually I need the fastest one. I guess in this case I should use `.Monotonic` or is there ieven faster type of ordering?

---

<div class="post-metadata">

**Author:** ![IntegratedQuantum](https://ziggit.dev/user_avatar/ziggit.dev/integratedquantum/32/782_2.png) [@IntegratedQuantum](https://ziggit.dev/u/IntegratedQuantum)\
**Post date:** [February 1, 2024, 11:06am UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/10 "2024-02-01T11:06:20Z")

</div>

There is also `.Unordered`. This doesn’t guarantee any order of reads/writes.  
It basically only guarantees that you don’t read garbage values. What you read must have been written somewhere before.

---

<div class="post-metadata">

**Author:** ![dude\_the\_builder](https://ziggit.dev/user_avatar/ziggit.dev/dude_the_builder/32/557_2.png) [@dude\_the\_builder](https://ziggit.dev/u/dude_the_builder)\
**Post date:** [February 1, 2024, 12:32pm UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/11 "2024-02-01T12:32:57Z")

</div>

You should also test the performance of doing the load with `.Acquire` and the store with `.Release`. This should be faster than `SeqCst` and slower than `Monotonic` or `Unordered`, but are often recommended as the best practice for load / store sequences and offers sane guarantees on ordering of operations.

---

<div class="post-metadata">

**Author:** ![jabolcni](https://ziggit.dev/user_avatar/ziggit.dev/jabolcni/32/1694_2.png) [@jabolcni](https://ziggit.dev/u/jabolcni)\
**Post date:** [February 1, 2024, 12:43pm UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/12 "2024-02-01T12:43:36Z")

</div>

I am now testing mutex-es using

`var lock = std.Thread.Mutex{};`

```zig
    inline fn setMutex(self: *TranspositionTable, entry: scoreEntry) void {
        _ = lock.lock();
        self.ttArray[self.index(entry.hash_key)] = @as(*const u128, @ptrCast(&entry)).*;
        lock.unlock();
    }

```

```zig
    inline fn getMutex(self: *TranspositionTable, hash: u64) scoreEntry {
        _ = lock.lock();
        var raw = @as(*scoreEntry, @ptrCast(&self.ttArray[self.index(hash)]));
        lock.unlock();
        return @as(*scoreEntry, raw).*;
    }

```

Once I figured out how to do pointer casting, the rest is quite easy and understandable.

Using atomics for storing/loading is relatively fast, almost no performance hit. I am not so sure about mutex, but I will have to wait for the results of the tests.

---

<div class="post-metadata">

**Author:** ![dude\_the\_builder](https://ziggit.dev/user_avatar/ziggit.dev/dude_the_builder/32/557_2.png) [@dude\_the\_builder](https://ziggit.dev/u/dude_the_builder)\
**Post date:** [February 1, 2024, 12:56pm UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/13 "2024-02-01T12:56:31Z")

</div>

Just a tip for common cases of using a mutex in Zig; you can take advantage of `defer` to ensure the mutex is unlocked no matter what happens. In your case, this isn’t really necessary because the code between `lock` and `unlock` (the critical section) is just one infallible operation. But for larger critical sections and ones containingg code that can fail, you can do:

```zig
{
    mutex.lock();
    defer mutex.unlock();
    // critical section
}
```

---

<div class="post-metadata">

**Author:** ![mperillo](https://ziggit.dev/user_avatar/ziggit.dev/mperillo/32/1280_2.png) [@mperillo](https://ziggit.dev/u/mperillo)\
**Post date:** [February 1, 2024, 3:36pm UTC](https://ziggit.dev/t/store-load-using-shared-memory-for-multithreade-application/3073/14 "2024-02-01T15:36:46Z")

</div>

> [@jabolcni](#):
>
> I am now testing mutex-es using
> 
> `var lock = std.Thread.Mutex{};`
> 
> ```zig
> inline fn setMutex(self: *TranspositionTable, entry: scoreEntry) void {
> _ = lock.lock();
> self.ttArray[self.index(entry.hash_key)] = @as(*const u128, @ptrCast(&entry)).*;
> lock.unlock();
> }
> 
> ```
> 
> ```zig
> inline fn getMutex(self: *TranspositionTable, hash: u64) scoreEntry {
> _ = lock.lock();
> var raw = @as(*scoreEntry, @ptrCast(&self.ttArray[self.index(hash)]));
> lock.unlock();
> return @as(*scoreEntry, raw).*;
> }
> 
> ```

Using a mutex will block all the access to the array, even if all the worker threads access different array elements.
