tango.core.Atomic

The atomic module is intended to provide some basic support for lock-free concurrent programming. Some common operations are defined, each of which may be performed using the specified memory barrier or a less granular barrier if the hardware does not support the version requested. This model is based on a design by Alexander Terekhov as outlined in this thread. Another useful reference for memory ordering on modern architectures is this article by Paul McKenney.

License:

BSD style: see license.txt

Authors:

Sean Kelly
enum msync #
Memory synchronization flag. If the supplied option is not available on the current platform then a stronger method will be used instead.
raw #
not sequenced
hlb #
hoist-load barrier
hsb #
hoist-store barrier
slb #
sink-load barrier
ssb #
sink-store barrier
acq #
hoist-load + hoist-store barrier
rel #
sink-load + sink-store barrier
seq #
fully sequenced (acq + rel)
template atomicLoad(msync ms, T) #
Supported msync values: msync.raw msync.hlb msync.acq msync.seq
T atomicLoad(ref T val) #
Refreshes the contents of 'val' from main memory. This operation is both lock-free and atomic.

Params:

valThe value to load. This value must be properly aligned.

Returns:

The loaded value.
template atomicStore(msync ms, T) #
Supported msync values: msync.raw msync.ssb msync.acq msync.rel msync.seq
void atomicStore(ref T val, T newval) #
Stores 'newval' to the memory referenced by 'val'. This operation is both lock-free and atomic.

Params:

valThe destination variable.
newvalThe value to store.
template atomicStoreIf(msync ms, T) #
Supported msync values: msync.raw msync.ssb msync.acq msync.rel msync.seq
bool atomicStoreIf(ref T val, T newval, T equalTo) #
Stores 'newval' to the memory referenced by 'val' if val is equal to 'equalTo'. This operation is both lock-free and atomic.

Params:

valThe destination variable.
newvalThe value to store.
equalToThe comparison value.

Returns:

true if the store occurred, false if not.
template atomicIncrement(msync ms, T) #
Supported msync values: msync.raw msync.ssb msync.acq msync.rel msync.seq
T atomicIncrement(ref T val) #
This operation is only legal for built-in value and pointer types, and is equivalent to an atomic "val = val + 1" operation. This function exists to facilitate use of the optimized increment instructions provided by some architecures. If no such instruction exists on the target platform then the behavior will perform the operation using more traditional means. This operation is both lock-free and atomic.

Params:

valThe value to increment.

Returns:

The result of an atomicLoad of val immediately following the increment operation. This value is not required to be equal to the newly stored value. Thus, competing writes are allowed to occur between the increment and successive load operation.
template atomicDecrement(msync ms, T) #
Supported msync values: msync.raw msync.ssb msync.acq msync.rel msync.seq
T atomicDecrement(ref T val) #
This operation is only legal for built-in value and pointer types, and is equivalent to an atomic "val = val - 1" operation. This function exists to facilitate use of the optimized decrement instructions provided by some architecures. If no such instruction exists on the target platform then the behavior will perform the operation using more traditional means. This operation is both lock-free and atomic.

Params:

valThe value to decrement.

Returns:

The result of an atomicLoad of val immediately following the increment operation. This value is not required to be equal to the newly stored value. Thus, competing writes are allowed to occur between the increment and successive load operation.
struct Atomic(T) #
This struct represents a value which will be subject to competing access. All accesses to this value will be synchronized with main memory, and various memory barriers may be employed for instruction ordering. Any primitive type of size equal to or smaller than the memory bus size is allowed, so 32-bit machines may use values with size <= int.sizeof and 64-bit machines may use values with size <= long.sizeof. The one exception to this rule is that architectures that support DCAS will allow double-wide storeIf operations. The 32-bit x86 architecture, for example, supports 64-bit storeIf operations.
template load(msync ms = msync.seq) #
T load() #
Refreshes the contents of this value from main memory. This operation is both lock-free and atomic.

Returns:

The loaded value.
template store(msync ms = msync.seq) #
void store(T newval) #
Stores 'newval' to the memory referenced by this value. This operation is both lock-free and atomic.

Params:

newvalThe value to store.
template storeIf(msync ms = msync.seq) #
bool storeIf(T newval, T equalTo) #
Stores 'newval' to the memory referenced by this value if val is equal to 'equalTo'. This operation is both lock-free and atomic.

Params:

newvalThe value to store.
equalToThe comparison value.

Returns:

true if the store occurred, false if not.