☰

# std/atomics

Theme:

- Manual
- Standard library
- Index
- Compiler docs
- Fusion docs
- devel, stable

Search:
Source Edit

Types and operations for atomic operations and lockless algorithms.

Unstable API.

By default, C++ uses C11 atomic primitives. To use C++ `std::atomic`, `-d:nimUseCppAtomics` can be defined.

Example:

    import std/atomics
    # Atomic
    var loc: Atomic[int]
    loc.store(4)
    assert loc.load == 4
    loc.store(2)
    assert loc.load(moRelaxed) == 2
    loc.store(9)
    assert loc.load(moAcquire) == 9
    loc.store(0, moRelease)
    assert loc.load == 0

    assert loc.exchange(7) == 0
    assert loc.load == 7

    var expected = 7
    assert loc.compareExchange(expected, 5, moRelaxed, moRelaxed)
    assert expected == 7
    assert loc.load == 5

    assert not loc.compareExchange(expected, 12, moRelaxed, moRelaxed)
    assert expected == 5
    assert loc.load == 5

    assert loc.fetchAdd(1) == 5
    assert loc.fetchAdd(2) == 6
    assert loc.fetchSub(3) == 8

    loc.atomicInc(1)
    assert loc.load == 6

    # AtomicFlag
    var flag: AtomicFlag

    assert not flag.testAndSet
    assert flag.testAndSet
    flag.clear(moRelaxed)
    assert not flag.testAndSet

# Types

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

  An atomic object with underlying type `T`. Source Edit

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

  An atomic boolean state. Source Edit

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

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

# Procs

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

  Atomically increments the atomic integer by some `value`. Source Edit

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

  Atomically decrements the atomic integer by some `value`. Source Edit

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

  Atomically decrements the atomic integer by some `value`. Source Edit

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

  Atomically increments the atomic integer by some `value`. Source Edit

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

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

    proc compareExchange[T](location: var Atomic[T]; expected: var T; desired: T;
                            order: MemoryOrder = moSequentiallyConsistent): bool {.
        importcpp: "#.compare_exchange_strong(@)", header: "<atomic>", ...raises: [],
        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

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

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

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

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

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

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

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

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

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

  Ensures memory ordering without using atomic operations. Source Edit

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

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

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

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

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

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

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

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

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

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

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

  Atomically obtains the value of the atomic object. Source Edit

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

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

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

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

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

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