How to use Mutex correctly between functions

void StepOne(){
    mutex.Lock();
    StepTwo();
    mutex.Unlock();
}
void StepTwo(){
    mutex.AssertHeld();
    {
        mutex.Unlock();
        doSomething();
        mutex.Lock();
    }
}

The above code is from C++ sample, I'm trying to find a way to implement it in Rust. Here's my plan:

#![allow(unused)]
use std::sync::{Arc, Mutex};
use std::thread;

struct Foo{}
fn step_one(a: Arc<Mutex<Foo>>) {
    {
        let _a = a.lock().unwrap();
    }
    {
        step_two(a.clone());
    }
}
fn step_two(a: Arc<Mutex<Foo>>) {
    let _a = a.lock().unwrap();
}

fn main() {
    let mutex = Arc::new(Mutex::new(Foo{}));
    step_one(mutex);
}

What is the most efficient and recommended way to share mutex between functions?
It seems that Rust mutex is locked many times, how about this for efficiency?

The Rust mutex is specifically intended for protecting a piece of data, and it's API is designed for that purpose. The mutex is unlocked in the destructor of the variable you called _a.

Maybe you can say a bit more about what you're doing?

The direct Rust equivalent is

use std::sync::{Arc, Mutex, MutexGuard};
use std::thread;

struct Foo{}
fn step_one(a: Arc<Mutex<Foo>>) {
    let lock = a.lock().unwrap();
    step_two(a.clone(), lock);
}
fn step_two(mutex: Arc<Mutex<Foo>>, guard: MutexGuard<'_, Foo>) {
    drop(guard);
    do_something();
    let _a = mutex.lock()
unwrap();
}

fn main() {
    let mutex = Arc::new(Mutex::new(Foo{}));
    step_one(mutex);
}

Yes, but (mutex: Arc<Mutex<Foo>>, guard: MutexGuard<'_, Foo>) seems duplicate, is there any elegant way? Any advice?

The std mutex is not intended for the use-case you have in mind. Consider using e.g. the RawMutex from the parking_lot crate. This mutex does not protect any data, and provides raw lock and unlock methods that don't involve a RAII guard.

Note that the methods on it are behind the impl RawMutex for RawMutex trait.

4 Likes

Depending on what do_something is, you might want Condvar, which seems to come up in some cases like this one where you want to unlock the mutex while doing something.

Unfortunately the mechanism that allows Condvar::wait to unlock a Mutex given only a MutexGuard is internal to std, so you can't write your own code that does the same thing.

Am I missing a point here. I have only ever seen mutexes (muticies ?) used to prevent simultaneous access to data by multiple threads. I see no threads mentioned here.

1 Like

Just a sample code.