6

Why was Mutex<T> designed to need an Arc<T> if the only reason to use a Mutex<T> is for concurrent code, i.e. multiple threads? Wouldn't it be better to alias a Mutex<T> to an atomic reference in the first place? I'm using https://doc.rust-lang.org/book/ch16-03-shared-state.html as reference.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
Lev
  • 1,698
  • 3
  • 18
  • 26

1 Answers1

22

You don't need an Arc to use a Mutex. The signature of lock (the most used method on a Mutex) is pub fn lock(&self) -> LockResult<MutexGuard<T>> which means you need a reference to the Mutex.

The problem arises with the borrow-checker. It is not able to prove certain guarantees when passing a reference to threads which might outlive the original Mutex. That's why you use Arc which guarantees that the value inside lives as long as the last Arc lives.

use lazy_static::lazy_static; // 1.3.0
use std::sync::Mutex;
use std::thread::spawn;

lazy_static! {
    static ref M: Mutex<u32> = Mutex::new(5);
}

fn a(m: &Mutex<u32>) {
    println!("{}", m.lock().unwrap());
}

fn b(m: &Mutex<u32>) {
    println!("{}", m.lock().unwrap());
}

fn main() {
    let t1 = spawn(|| a(&M));
    let t2 = spawn(|| b(&M));

    t1.join().unwrap();
    t2.join().unwrap();
}

(Playground)

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
hellow
  • 12,430
  • 7
  • 56
  • 79
  • 1
    I think scoped threads are a more obvious use of a `Mutex` (or `RwLock` or `Atomic`) without reference counting: [How can I pass a reference to a stack variable to a thread?](https://stackoverflow.com/q/32750829/155423). – Shepmaster Jun 13 '19 at 14:04