Alternative to Mutexs, When code is sound without them

lets say you have a variable named x: let mut x = Arc::new((1, 2)). And your threaded code looks like this:

thread::spawn(move || {
    x.0 = 10
});

thread::spawn(move || {
    x.1 = 10
});

The threads NEVER trip over each other. But the compiler doesn't know that.

How can I avoid needing to use a Mutex?

You need to use an Arc<UnsafeCell<...>> if you want shared mutability without any overhead. But unless you're very confident something else is already doing synchronization you can run into problems even if it's true that the threads are never running at exactly the same time.

UnsafeCell is the only type that's allowed to mutate through a shared reference, and all the other types like Mutex that do so use an UnsafeCell internally. As the name implies though, you have to use unsafe to do anything useful with it.

2 Likes

You don't need any unsafe. For primitive types, use individually-wrapped atomics instead:

let x = Arc::new((AtomicU64::new(1), AtomicU64::new(2)));
let y = x.clone();

thread::spawn(move || {
    x.0.store(10, Ordering::SeqCst);
});

thread::spawn(move || {
    y.1.store(10, Ordering::SeqCst);
});
3 Likes

If you use std::thread::scope and don't wrap the tuple in a Arc it should work.

3 Likes