Rust Guide > Documentation > Concurrency > AtomicU32

Introduction

In Rust, AtomicU32 is an atomic integer type that provides thread-safe operations on 32-bit unsigned integers. It is part of the standard library's std::sync::atomic module and is useful for shared state between threads where you need to perform atomic operations without using locks.

Using AtomicU32

To use AtomicU32, you need to import it from the std::sync::atomic module. You can create an AtomicU32 by using the AtomicU32::new method. Atomic operations such as store, load, fetch_add, and compare_and_swap can be used to manipulate the value safely across threads.

use std::sync::atomic::{AtomicU32, Ordering};

fn main() {
    let atomic = AtomicU32::new(5);

    println!("Initial value: {}", atomic.load(Ordering::Relaxed));

    atomic.store(10, Ordering::Relaxed);

    println!("Updated value: {}", atomic.load(Ordering::Relaxed));
}
// Output:
// Initial value: 5
// Updated value: 10

Key Methods

Below are some of the key methods exposed by the AtomicU32 class:

AtomicU32::new

Creates a new AtomicU32 with the given initial value.

use std::sync::atomic::AtomicU32;

fn main() {
    let atomic = AtomicU32::new(10);
    println!("Created AtomicU32 with initial value: {}", atomic.load(Ordering::Relaxed));
}
// Output:
// Created AtomicU32 with initial value: 10

load

Returns the current value of the AtomicU32.

use std::sync::atomic::{AtomicU32, Ordering};

fn main() {
    let atomic = AtomicU32::new(20);
    println!("Current value: {}", atomic.load(Ordering::Relaxed));
}
// Output:
// Current value: 20

store

Sets the value of the AtomicU32.

use std::sync::atomic::{AtomicU32, Ordering};

fn main() {
    let atomic = AtomicU32::new(30);
    atomic.store(40, Ordering::Relaxed);
    println!("Updated value: {}", atomic.load(Ordering::Relaxed));
}
// Output:
// Updated value: 40

compare_and_swap

Compares the current value with current, and if they are equal, sets it to new.

use std::sync::atomic::{AtomicU32, Ordering};

fn main() {
    let atomic = AtomicU32::new(50);
    let old_value = atomic.compare_and_swap(50, 60, Ordering::Relaxed);
    println!("Old value: {}, New value: {}", old_value, atomic.load(Ordering::Relaxed));
}
// Output:
// Old value: 50
// New value: 60

fetch_add

Adds to the current value, returning the previous value.

use std::sync::atomic::{AtomicU32, Ordering};

fn main() {
    let atomic = AtomicU32::new(70);
    let previous = atomic.fetch_add(10, Ordering::Relaxed);
    println!("Previous value: {}, New value: {}", previous, atomic.load(Ordering::Relaxed));
}
// Output:
// Previous value: 70
// New value: 80

fetch_sub

Subtracts from the current value, returning the previous value.

use std::sync::atomic::{AtomicU32, Ordering};

fn main() {
    let atomic = AtomicU32::new(100);
    let previous = atomic.fetch_sub(20, Ordering::Relaxed);
    println!("Previous value: {}, New value: {}", previous, atomic.load(Ordering::Relaxed));
}
// Output:
// Previous value: 100
// New value: 80

Example Usage

Example 1: Basic Usage

use std::sync::atomic::{AtomicU32, Ordering};

fn main() {
    let atomic = AtomicU32::new(5);

    println!("Initial value: {}", atomic.load(Ordering::Relaxed));

    atomic.store(10, Ordering::Relaxed);

    println!("Updated value: {}", atomic.load(Ordering::Relaxed));
}
// Output:
// Initial value: 5
// Updated value: 10

Example 2: Using compare_and_swap

use std::sync::atomic::{AtomicU32, Ordering};

fn main() {
    let atomic = AtomicU32::new(50);

    let old_value = atomic.compare_and_swap(50, 60, Ordering::Relaxed);
    println!("Old value: {}, New value: {}", old_value, atomic.load(Ordering::Relaxed));
}
// Output:
// Old value: 50
// New value: 60

Example 3: Using fetch_add

use std::sync::atomic::{AtomicU32, Ordering};

fn main() {
    let atomic = AtomicU32::new(70);

    let previous = atomic.fetch_add(10, Ordering::Relaxed);
    println!("Previous value: {}, New value: {}", previous, atomic.load(Ordering::Relaxed));
}
// Output:
// Previous value: 70
// New value: 80

Example 4: Using fetch_sub

use std::sync::atomic::{AtomicU32, Ordering};

fn main() {
    let atomic = AtomicU32::new(100);

    let previous = atomic.fetch_sub(20, Ordering::Relaxed);
    println!("Previous value: {}, New value: {}", previous, atomic.load(Ordering::Relaxed));
}
// Output:
// Previous value: 100
// New value: 80

Example 5: Using with Multiple Threads

use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
use std::thread;

fn main() {
    let atomic = Arc::new(AtomicU32::new(0));

    let atomic1 = Arc::clone(&atomic);
    let

<pre><code class="rust">
handle1 = thread::spawn(move || {
        atomic1.fetch_add(1, Ordering::Relaxed);
    });

    let atomic2 = Arc::clone(&atomic);
    let handle2 = thread::spawn(move || {
        atomic2.fetch_add(1, Ordering::Relaxed);
    });

    handle1.join().unwrap();
    handle2.join().unwrap();

    println!("Final value: {}", atomic.load(Ordering::Relaxed));
}
// Output:
// Final value: 2

Considerations

  • Operations on AtomicU32 are lock-free and thread-safe.
  • Always use the appropriate Ordering when performing atomic operations to ensure the correct memory ordering guarantees.
  • Use AtomicU32 when you need to share a simple integer state across threads without the overhead of using a mutex.

See Also

  • AtomicUsize - An atomic integer type for shared state between threads.
  • Mutex - A mutual exclusion primitive for protecting shared data.
  • RwLock - A read-write lock allowing multiple readers or a single writer.