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.