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
AtomicBoolare lock-free and thread-safe. - Always use the appropriate
Orderingwhen performing atomic operations to ensure the correct memory ordering guarantees. - Use
AtomicBoolwhen 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.
