Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Mutex was designed to need an Arc in Rust

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.

like image 452
Lev Avatar asked Jun 13 '19 06:06

Lev


People also ask

What is ARC mutex in Rust?

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 does ARC do in Rust?

'Arc' stands for 'Atomically Reference Counted'. The type Arc<T> provides shared ownership of a value of type T , allocated in the heap. Invoking clone on Arc produces a new Arc instance, which points to the same allocation on the heap as the source Arc , while increasing a reference count.

How does mutex work Rust?

Mutexes Allow Access to Data from One Thread at a Time. A mutex is an abbreviation for “mutual exclusion,” as in, it only allows one thread to access some data at any given time. To access the data in a mutex, a thread must first signal that it wants access by asking to acquire the mutex's lock.

Why are mutex required?

It ensures that only one thread is executing a key piece of code at a time, which in turns limits access to a data structure. It ensures that the both threads have a full and proper view of that memory irrespective of any CPU reordering. The mutex is an absolute necessity when doing concurrent programming.


1 Answers

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)

like image 74
hellow Avatar answered Oct 24 '22 08:10

hellow