[Solved] Confused by AtomicUsize

I am not sure why my code doesn't work with AtomicUsize, but works with Mutex.

[code]#![feature(atomic_access)]

use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::atomic::AtomicUsize;

fn main() {
let mut thread_handles = Vec::new();
let n = Arc::new(AtomicUsize::new(0));

for _ in 0..2 {
    let x = n.clone();
    thread_handles.push(thread::spawn(move || {
        for _ in 0..1000 {
            let mut i = x.get_mut();
            *i += 1;
        }
    }));
}

for thread in thread_handles {
    thread.join();
}

println!("n = {}", Arc::try_unwrap(n).unwrap().into_inner());

}[/code]

cargo run gives me the following output:

[code]cargo run
Compiling stuff v0.1.0 (.../stuff)
error: cannot borrow immutable borrowed content as mutable
--> src/main.rs:15:29
|
15 | let mut i = x.get_mut();
| ^

error: aborting due to previous error

error: Could not compile stuff.

To learn more, run the command again with --verbose.[/code]

AtomicUsize::get_mut requires a unique reference (&mut AtomicUsize), to guarantee that it can't be called on multiple threads at once. This is similar to Mutex::get_mut, which would cause a similar error.

When an Arc is shared, it can only give out shared references (&AtomicUsize). This shared reference will only let you do atomic operations like fetch_add. Here's an example (playground):

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

fn main() {
    let mut thread_handles = Vec::new();
    let n = Arc::new(AtomicUsize::new(0));
    for _ in 0..2 {
        let x = n.clone();
        thread_handles.push(thread::spawn(move || {
            for _ in 0..1000 {
                x.fetch_add(1, Ordering::SeqCst);
            }
        }));
    }
    
    for thread in thread_handles {
        thread.join();
    }
    
    println!("n = {}", n.load(Ordering::SeqCst));
}
2 Likes

ahh, thanks for the clarification!