Why Mutex doesn't implement clone trait

Rust requires to use Arc::new() to wrap the mutex. If mutex can be clone(), we could call mutex.clone() and pass the reference to sub-threads directly. Anything blocks a trait implementation for std::sync::Mutex ?

let data = Arc::new(Mutex::new(0i32));
let (tx, rx) = mpsc::channel();

for _ in 0..10 {
    let (data, tx) = (data.clone(), tx.clone());
    thread::spawn(move || {
        let mut data = data.lock().unwrap();
        *data += 1;
        tx.send(());
    });
}

So, if mutex could be clone, we can write the code:

let data = Mutex::new(0i32);
let (tx, rx) = mpsc::channel();

for _ in 0..10 {
    let (data, tx) = (data.clone(), tx.clone());
    thread::spawn(move || {
        let mut data = data.lock().unwrap();
        *data += 1;
        tx.send(());
    });
}

Why should Mutex::clone clone the pointer (as Arc::clone does) and not the data?

1 Like

MutexGuard implements DerefMut trait, meaning you can mutate data behind it. And Mutex::lock and try_lock which return MutexGuard use only &self. In other words you can share "read-only" reference to a mutex with other threads.

One possible pattern is to box mutex and leak it:

let foo_mutex: &'static Mutex<Foo> = Box::leak(Box::new(Mutex::new(foo)));
thread::spawn(move || {
    // you can lock mutex and read/write data behind it in this thread
});
// and in the parent one

An ability to clone mutex would mean that it will have to keep number of active clones to be able to properly drop underlying data, thus it would copy Arc functionality. So it's a basic separation of concerns.

3 Likes

Mutex<T> doesn't implies heap allocation. Unfortunately current implementation of the stdlib's mutex has some boxed system primitive, but it still holds its data inline.

#[stable(feature = "rust1", since = "1.0.0")]
pub struct Mutex<T: ?Sized> {
    // Note that this mutex is in a *box*, not inlined into the struct itself.
    // Once a native mutex has been used once, its address can never change (it
    // can't be moved). This mutex type can be safely moved at any time, so to
    // ensure that the native mutex is used correctly we box the inner mutex to
    // give it a constant address.
    inner: Box<sys::Mutex>,
    poison: poison::Flag,
    data: UnsafeCell<T>,
}

And we have a plan to replace it with the parking_lot crate's mutex implementation which doesn't have heap allocation at all.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.