How do I remove `MutexGuard` around a value?

Viewed 1629

I'm trying to use ndarray as an asynchronous process to do linear algebra and such. I used Rust's tokio and ndarray to create the following code.

use std::sync::{Arc, Mutex};
use ndarray::prelude::*;
use futures::future::join_all;

fn print_type_of<T>(_: &T) {
    println!("{}", std::any::type_name::<T>())
}


#[tokio::main]
async fn main() {
    let db = Arc::new(Mutex::new(array![0,0,0,0,0,0,0,0]));
    let mut handels = vec![];

    for i in 0..8 {
        let db = db.clone();
        let unchange_array = unchange_array.clone();
        handels.push(tokio::spawn(async move{
            print(i, db).await;
        }));
    }
    join_all(handels).await;
    let array = Arc::try_unwrap(db).unwrap();
    let array = array.lock().unwrap();
    print_type_of(&array);  // -> std::sync::mutex::MutexGuard<ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<u32>, ndarray::dimension::dim::Dim<[usize; 1]>>>

}

async fn print(i: u32, db: Arc<Mutex<Array1<u32>>>) {
    let unchange = unchange.to_owned();
    let mut tmp = 0;
    // time-consuming process
    for k in 0..100000000 {
        tmp = k; 
    }
    tmp += i;
    let mut db = db.lock().unwrap();
    db.fill(i);
    println!("{:?}", unchange);
    print_type_of(&db);
}

I would like to change the data std::sync::mutex::MutexGuard<ndarray::ArrayBase<OwnedRepr<u32>, Dim<[usize; 1]>>> to ndarray::ArrayBase<OwnedRepr<u32>, Dim<[usize; 1]>>.

How can I do this?

1 Answers

You can't. That's the whole point of MutexGuard: if you could take the data out of the MutexGuard, then you would be able to make a reference that can be accessed without locking the mutex, defeating the whole purpose of having a mutex in the first place.

Depending on what you really want to do, one of the following solutions might apply to you:

  • Most of the time, you don't need to take the data out of the mutex: MutexGuard<T> implements Deref<Target=T> and DerefMut<Target=T>, so you can use the MutexGuard everywhere you would use a &T or a &mut T. Note that if you change your code to call print_type_of(&*array) instead of print_type_of(&array), it will print the inner type.

  • If you really need to, you can take the data out of the Mutex itself (but not the MutexGuard) with into_inner, which consumes the mutex, ensuring that no one else can ever access it:

let array = Arc::try_unwrap(db).unwrap();
let array = array.into_inner().unwrap();
print_type_of(&array);  // -> ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<u32>, ndarray::dimension::dim::Dim<[usize; 1]>>
Related