When would you use a Mutex without an Arc?

An extremely common pattern in Rust is Arc<Mutex<T>>, where Arc provides the memory management, and Mutex provides safe multi-threaded access to the resource. What else could be used in place of Arc, and under what circumstances?


Solution 1:

Arc is of course the most common one in this context, but there are other pointer types that allow sharing. The major (and most common, in the rest of Rust) one is the shared reference &T. This normally doesn't work with std::thread::spawn'd threads, because it generally points to data controlled by some other thread, and is hence usually not 'static (particularly so when it is a &Mutex<T>). However, one can use a scoped thread to create a thread that can share data with its parent. E.g.

use crossbeam; // 0.7.3
use std::sync::Mutex;

fn main() {
    let data = Mutex::new(vec![0, 1]);

    crossbeam::scope(|scope| {
        // these run concurrently:
        let _guard = scope.spawn(|_| {
            data.lock().unwrap().push(2);
        });
        data.lock().unwrap().push(3);
    })
    .unwrap();

    println!("{:?}", data.lock().unwrap());
    // one of [0, 1, 2, 3] or [0, 1, 3, 2]
}

The type of data in the closure passed to scope.spawn is in fact &Mutex<Vec<i32>> (since it doesn't have the move keyword the closure is using the default capturing style: by reference).

& and Arc are the two that can achieve this sort of thread-safe sharing in the standard library/language, but one can also write pointer types that offer thread-safe sharing in external libraries.

However, moving away from the Pointer<Mutex<...>> pattern, it can be useful to have the mutex and the sharing separated, e.g. Arc<Vec<Mutex<T>>> allows one to share some number of Mutex<T>'s without having to Arc each one individually, or maybe one wants to have some abstraction around a Mutex, and so wrap it in a struct:

struct Wrapped {
    data: Mutex<T>,
}
impl Wrapped {
    // fancy methods that abstract over `data.lock()`
}

One would likely then see Arc<Wrapped> (or some other pointer that allows sharing).