Rust Guide > Documentation > Concurrency > AtomicBool

Introduction

In Rust, AtomicBool is a boolean type that can be safely shared between threads. It provides atomic operations for setting, updating, and reading the boolean value. AtomicBool is part of the standard library's std::sync::atomic module and is useful in scenarios where you need to perform thread-safe boolean operations without using locks.

Using AtomicBool

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

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

fn main() {
    let flag = AtomicBool::new(true);

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

    flag.store(false, Ordering::Relaxed);

    println!("Updated value: {}", flag.load(Ordering::Relaxed));
}
// Output:
// Initial value: true
// Updated value: false

Key Methods

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

AtomicBool::new

Creates a new AtomicBool with the given initial value.

use std::sync::atomic::AtomicBool;

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

load

Returns the current value of the AtomicBool.

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

fn main() {
    let flag = AtomicBool::new(false);
    println!("Current value: {}", flag.load(Ordering::Relaxed));
}
// Output:
// Current value: false

store

Sets the value of the AtomicBool.

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

fn main() {
    let flag = AtomicBool::new(true);
    flag.store(false, Ordering::Relaxed);
    println!("Updated value: {}", flag.load(Ordering::Relaxed));
}
// Output:
// Updated value: false

compare_and_swap

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

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

fn main() {
    let flag = AtomicBool::new(true);
    let old_value = flag.compare_and_swap(true, false, Ordering::Relaxed);
    println!("Old value: {}, New value: {}", old_value, flag.load(Ordering::Relaxed));
}
// Output:
// Old value: true
// New value: false

Example Usage

Example 1: Basic Usage

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

fn main() {
    let flag = AtomicBool::new(true);

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

    flag.store(false, Ordering::Relaxed);

    println!("Updated value: {}", flag.load(Ordering::Relaxed));
}
// Output:
// Initial value: true
// Updated value: false

Example 2: Using compare_and_swap

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

fn main() {
    let flag = AtomicBool::new(false);

    let old_value = flag.compare_and_swap(false, true, Ordering::Relaxed);
    println!("Old value: {}, New value: {}", old_value, flag.load(Ordering::Relaxed));
}
// Output:
// Old value: false
// New value: true

Example 3: Using fetch_or

The fetch_or method sets the AtomicBool to true if the current value is false.

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

fn main() {
    let flag = AtomicBool::new(false);

    flag.fetch_or(true, Ordering::Relaxed);
    println!("Value after fetch_or: {}", flag.load(Ordering::Relaxed));
}
// Output:
// Value after fetch_or: true

Example 4: Using fetch_and

The fetch_and method sets the AtomicBool to false if the current value is true.

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

fn main() {
    let flag = AtomicBool::new(true);

    flag.fetch_and(false, Ordering::Relaxed);
    println!("Value after fetch_and: {}", flag.load(Ordering::Relaxed));
}
// Output:
// Value after fetch_and: false

Example 5: Using with Multiple Threads

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

fn main() {
    let flag = Arc::new(AtomicBool::new(false));

    let flag1 = Arc::clone(&flag);
    let handle1 = thread::spawn(move || {
        flag1.store(true, Ordering::Relaxed);
    });

    let flag2 = Arc::clone(&flag);
    let handle2 = thread::spawn(move || {
        while !flag2.load(Ordering::Relaxed) {}
        println!("Flag is set to true");
    });

    handle1.join().unwrap();
    handle2.join().unwrap();
}
// Output:
// Flag is set to true

Considerations

  • Operations on AtomicBool are lock-free and thread-safe.
  • Always use the appropriate Ordering when performing atomic operations to ensure the correct memory ordering guarantees.
  • Use AtomicBool when you need to share a simple boolean 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.