Atomic types
Atomic types provide primitive shared-memory communication between threads, and are the building blocks of other concurrent types.
This module defines atomic versions of a select number of primitive types, including AtomicBool
, AtomicIsize
, AtomicUsize
, AtomicI8
, AtomicU16
, etc. Atomic types present operations that, when used correctly, synchronize updates between threads.
Each method takes an Ordering
which represents the strength of the memory barrier for that operation. These orderings are the same as the C++20 atomic orderings. For more information see the nomicon.
Atomic variables are safe to share between threads (they implement Sync
) but they do not themselves provide the mechanism for sharing and follow the threading model of Rust. The most common way to share an atomic variable is to put it into an Arc
(an atomically-reference-counted shared pointer).
Atomic types may be stored in static variables, initialized using the constant initializers like AtomicBool::new
. Atomic statics are often used for lazy global initialization.
All atomic types in this module are guaranteed to be lock-free if they're available. This means they don't internally acquire a global mutex. Atomic types and operations are not guaranteed to be wait-free. This means that operations like fetch_or
may be implemented with a compare-and-swap loop.
Atomic operations may be implemented at the instruction layer with larger-size atomics. For example some platforms use 4-byte atomic instructions to implement AtomicI8
. Note that this emulation should not have an impact on correctness of code, it's just something to be aware of.
The atomic types in this module may not be available on all platforms. The atomic types here are all widely available, however, and can generally be relied upon existing. Some notable exceptions are:
AtomicU64
or AtomicI64
types.armv5te
that aren't for Linux do not have any atomics at all.thumbv6m
do not have atomic operations at all.Note that future platforms may be added that also do not have support for some atomic operations. Maximally portable code will want to be careful about which atomic types are used. AtomicUsize
and AtomicIsize
are generally the most portable, but even then they're not available everywhere. For reference, the std
library requires pointer-sized atomics, although core
does not.
Currently you'll need to use #[cfg(target_arch)]
primarily to conditionally compile in code with atomics. There is an unstable #[cfg(target_has_atomic)]
as well which may be stabilized in the future.
A simple spinlock:
use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread; fn main() { let spinlock = Arc::new(AtomicUsize::new(1)); let spinlock_clone = spinlock.clone(); let thread = thread::spawn(move|| { spinlock_clone.store(0, Ordering::SeqCst); }); // Wait for the other thread to release the lock while spinlock.load(Ordering::SeqCst) != 0 {} if let Err(panic) = thread.join() { println!("Thread had an error: {:?}", panic); } }
Keep a global count of live threads:
use std::sync::atomic::{AtomicUsize, Ordering}; static GLOBAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0); let old_thread_count = GLOBAL_THREAD_COUNT.fetch_add(1, Ordering::SeqCst); println!("live threads: {}", old_thread_count + 1);
AtomicBool |
A boolean type which can be safely shared between threads. |
AtomicI8 |
An integer type which can be safely shared between threads. |
AtomicI16 |
An integer type which can be safely shared between threads. |
AtomicI32 |
An integer type which can be safely shared between threads. |
AtomicI64 |
An integer type which can be safely shared between threads. |
AtomicIsize |
An integer type which can be safely shared between threads. |
AtomicPtr |
A raw pointer type which can be safely shared between threads. |
AtomicU8 |
An integer type which can be safely shared between threads. |
AtomicU16 |
An integer type which can be safely shared between threads. |
AtomicU32 |
An integer type which can be safely shared between threads. |
AtomicU64 |
An integer type which can be safely shared between threads. |
AtomicUsize |
An integer type which can be safely shared between threads. |
Ordering |
Atomic memory orderings |
ATOMIC_BOOL_INIT |
Deprecated An |
ATOMIC_ISIZE_INIT |
Deprecated An atomic integer initialized to |
ATOMIC_USIZE_INIT |
Deprecated An atomic integer initialized to |
ATOMIC_I8_INIT |
DeprecatedExperimental An atomic integer initialized to |
ATOMIC_I16_INIT |
DeprecatedExperimental An atomic integer initialized to |
ATOMIC_I32_INIT |
DeprecatedExperimental An atomic integer initialized to |
ATOMIC_I64_INIT |
DeprecatedExperimental An atomic integer initialized to |
ATOMIC_U8_INIT |
DeprecatedExperimental An atomic integer initialized to |
ATOMIC_U16_INIT |
DeprecatedExperimental An atomic integer initialized to |
ATOMIC_U32_INIT |
DeprecatedExperimental An atomic integer initialized to |
ATOMIC_U64_INIT |
DeprecatedExperimental An atomic integer initialized to |
compiler_fence |
A compiler memory fence. |
fence |
An atomic fence. |
spin_loop_hint |
Signals the processor that it is inside a busy-wait spin-loop ("spin lock"). |
© 2010 The Rust Project Developers
Licensed under the Apache License, Version 2.0 or the MIT license, at your option.
https://doc.rust-lang.org/std/sync/atomic/index.html