Source Edit

Types and operations for atomic operations and lockless algorithms.

Unstable API.

Example:

  1. import std/atomics
  2. # Atomic
  3. var loc: Atomic[int]
  4. loc.store(4)
  5. assert loc.load == 4
  6. loc.store(2)
  7. assert loc.load(moRelaxed) == 2
  8. loc.store(9)
  9. assert loc.load(moAcquire) == 9
  10. loc.store(0, moRelease)
  11. assert loc.load == 0
  12. assert loc.exchange(7) == 0
  13. assert loc.load == 7
  14. var expected = 7
  15. assert loc.compareExchange(expected, 5, moRelaxed, moRelaxed)
  16. assert expected == 7
  17. assert loc.load == 5
  18. assert not loc.compareExchange(expected, 12, moRelaxed, moRelaxed)
  19. assert expected == 5
  20. assert loc.load == 5
  21. assert loc.fetchAdd(1) == 5
  22. assert loc.fetchAdd(2) == 6
  23. assert loc.fetchSub(3) == 8
  24. loc.atomicInc(1)
  25. assert loc.load == 6
  26. # AtomicFlag
  27. var flag: AtomicFlag
  28. assert not flag.testAndSet
  29. assert flag.testAndSet
  30. flag.clear(moRelaxed)
  31. assert not flag.testAndSet

Types

  1. Atomic[T] {.importcpp: "std::atomic", completeStruct.} = object

An atomic object with underlying type T. Source Edit

  1. AtomicFlag {.importcpp: "std::atomic_flag", size: 1.} = object

An atomic boolean state. Source Edit

  1. MemoryOrder {.importcpp: "std::memory_order".} = enum
  2. moRelaxed, ## No ordering constraints. Only the atomicity and ordering against
  3. ## other atomic operations is guaranteed.
  4. moConsume, ## This ordering is currently discouraged as it's semantics are
  5. ## being revised. Acquire operations should be preferred.
  6. moAcquire, ## When applied to a load operation, no reads or writes in the
  7. ## current thread can be reordered before this operation.
  8. moRelease, ## When applied to a store operation, no reads or writes in the
  9. ## current thread can be reorderd after this operation.
  10. moAcquireRelease, ## When applied to a read-modify-write operation, this behaves like
  11. ## both an acquire and a release operation.
  12. moSequentiallyConsistent ## Behaves like Acquire when applied to load, like Release when
  13. ## applied to a store and like AcquireRelease when applied to a
  14. ## read-modify-write operation.
  15. ## Also guarantees that all threads observe the same total ordering
  16. ## with other moSequentiallyConsistent operations.

Specifies how non-atomic operations can be reordered around atomic operations. Source Edit

Procs

  1. proc `+=`[T: SomeInteger](location: var Atomic[T]; value: T) {.inline.}

Atomically increments the atomic integer by some value. Source Edit

  1. proc `-=`[T: SomeInteger](location: var Atomic[T]; value: T) {.inline.}

Atomically decrements the atomic integer by some value. Source Edit

  1. proc atomicDec[T: SomeInteger](location: var Atomic[T]; value: T = 1) {.inline.}

Atomically decrements the atomic integer by some value. Source Edit

  1. proc atomicInc[T: SomeInteger](location: var Atomic[T]; value: T = 1) {.inline.}

Atomically increments the atomic integer by some value. Source Edit

  1. proc clear(location: var AtomicFlag;
  2. order: MemoryOrder = moSequentiallyConsistent) {.
  3. importcpp: "#.clear(@)", header: "<atomic>", ...raises: [], tags: [],
  4. forbids: [].}

Atomically sets the value of the atomic flag to false. Source Edit

  1. proc compareExchange[T](location: var Atomic[T]; expected: var T; desired: T;
  2. order: MemoryOrder = moSequentiallyConsistent): bool {.
  3. importcpp: "#.compare_exchange_strong(@)", header: "<atomic>", ...raises: [],
  4. tags: [], forbids: [].}

Atomically compares the value of the atomic object with the expected value and performs exchange with the desired one if equal or load if not. Returns true if the exchange was successful. Source Edit

  1. proc compareExchange[T](location: var Atomic[T]; expected: var T; desired: T;
  2. success, failure: MemoryOrder): bool {.
  3. importcpp: "#.compare_exchange_strong(@)", header: "<atomic>", ...raises: [],
  4. tags: [], forbids: [].}

Same as above, but allows for different memory orders for success and failure. Source Edit

  1. proc compareExchangeWeak[T](location: var Atomic[T]; expected: var T;
  2. desired: T;
  3. order: MemoryOrder = moSequentiallyConsistent): bool {.
  4. importcpp: "#.compare_exchange_weak(@)", header: "<atomic>", ...raises: [],
  5. tags: [], forbids: [].}

Same as above, but is allowed to fail spuriously. Source Edit

  1. proc compareExchangeWeak[T](location: var Atomic[T]; expected: var T;
  2. desired: T; success, failure: MemoryOrder): bool {.
  3. importcpp: "#.compare_exchange_weak(@)", header: "<atomic>", ...raises: [],
  4. tags: [], forbids: [].}

Same as above, but allows for different memory orders for success and failure. Source Edit

  1. proc exchange[T](location: var Atomic[T]; desired: T;
  2. order: MemoryOrder = moSequentiallyConsistent): T {.
  3. importcpp: "#.exchange(@)", header: "<atomic>", ...raises: [], tags: [],
  4. forbids: [].}

Atomically replaces the value of the atomic object with the desired value and returns the old value. Source Edit

  1. proc fence(order: MemoryOrder) {.importcpp: "std::atomic_thread_fence(@)",
  2. header: "<atomic>", ...raises: [], tags: [],
  3. forbids: [].}

Ensures memory ordering without using atomic operations. Source Edit

  1. proc fetchAdd[T: SomeInteger](location: var Atomic[T]; value: T;
  2. order: MemoryOrder = moSequentiallyConsistent): T {.
  3. importcpp: "#.fetch_add(@)", header: "<atomic>", ...raises: [], tags: [],
  4. forbids: [].}

Atomically adds a value to the atomic integer and returns the original value. Source Edit

  1. proc fetchAnd[T: SomeInteger](location: var Atomic[T]; value: T;
  2. order: MemoryOrder = moSequentiallyConsistent): T {.
  3. importcpp: "#.fetch_and(@)", header: "<atomic>", ...raises: [], tags: [],
  4. forbids: [].}

Atomically replaces the atomic integer with it’s bitwise AND with the specified value and returns the original value. Source Edit

  1. proc fetchOr[T: SomeInteger](location: var Atomic[T]; value: T;
  2. order: MemoryOrder = moSequentiallyConsistent): T {.
  3. importcpp: "#.fetch_or(@)", header: "<atomic>", ...raises: [], tags: [],
  4. forbids: [].}

Atomically replaces the atomic integer with it’s bitwise OR with the specified value and returns the original value. Source Edit

  1. proc fetchSub[T: SomeInteger](location: var Atomic[T]; value: T;
  2. order: MemoryOrder = moSequentiallyConsistent): T {.
  3. importcpp: "#.fetch_sub(@)", header: "<atomic>", ...raises: [], tags: [],
  4. forbids: [].}

Atomically subtracts a value to the atomic integer and returns the original value. Source Edit

  1. proc fetchXor[T: SomeInteger](location: var Atomic[T]; value: T;
  2. order: MemoryOrder = moSequentiallyConsistent): T {.
  3. importcpp: "#.fetch_xor(@)", header: "<atomic>", ...raises: [], tags: [],
  4. forbids: [].}

Atomically replaces the atomic integer with it’s bitwise XOR with the specified value and returns the original value. Source Edit

  1. proc load[T](location: var Atomic[T];
  2. order: MemoryOrder = moSequentiallyConsistent): T {.
  3. importcpp: "#.load(@)", header: "<atomic>", ...raises: [], tags: [],
  4. forbids: [].}

Atomically obtains the value of the atomic object. Source Edit

  1. proc signalFence(order: MemoryOrder) {.importcpp: "std::atomic_signal_fence(@)",
  2. header: "<atomic>", ...raises: [], tags: [],
  3. forbids: [].}

Prevents reordering of accesses by the compiler as would fence, but inserts no CPU instructions for memory ordering. Source Edit

  1. proc store[T](location: var Atomic[T]; desired: T;
  2. order: MemoryOrder = moSequentiallyConsistent) {.
  3. importcpp: "#.store(@)", header: "<atomic>", ...raises: [], tags: [],
  4. forbids: [].}

Atomically replaces the value of the atomic object with the desired value. Source Edit

  1. proc testAndSet(location: var AtomicFlag;
  2. order: MemoryOrder = moSequentiallyConsistent): bool {.
  3. importcpp: "#.test_and_set(@)", header: "<atomic>", ...raises: [], tags: [],
  4. forbids: [].}

Atomically sets the atomic flag to true and returns the original value. Source Edit