Take ownership of Arc<Mutex<T>> inner value

Hello everyone,

Let T be a struct that doesn't implement the copy trait, but implement the clone tait. We consider a function like this :

fn f() -> T
{
    let l = Vec::new(Muter::new(T::new()));
    /*
    operations that construct the wanted value in the inner value
    */
    // We now want return the value of the inner value 
    // This work : 
    return (*l.lock().unwrap()).clone();
}

But I want to simply giving ownership of the inner value, if the value is big I wouldn't clone it. Is it a solution to just move the inner value by giving ownership at the end of function ?

Thank you !

Hello, you could try this:

fn f() -> T
{
    let l = Vec::new(Muter::new(T::new()));
    /*
    operations that construct the wanted value in the inner value
    */
    // We now want return the value of the inner value 
    // This work : 
    //return (*l.lock().unwrap()).clone();
    l.try_unwrap().unwrap().into_inner().unwrap()
}

There are some examples like this and this in the documentation.

1 Like

The challenge is that when you have an Arc, there may be other Arcs to the same thing. You can only take ownership if you are the only one with access. As @notoria suggested, you can use Arc::try_unwrap to unwrap the Arc, but this will fail if there are more than one Arc handle to that object.

Another option is to use mem::take or mem::replace to move the value out of the mutex and leave another value in its place. (This is useful if constructing a new/empty value is less expensive than cloning the existing value.)

Thank you for your answers, that's better, but I have this error :

error[E0599]: no method named `unwrap` found for type     `std::result::Result<std::sync::Mutex<linear_algebra::upper_triangular::UpperTriangular>,     std::sync::Arc<std::sync::Mutex<linear_algebra::upper_triangular::UpperTriangular>>>` in the current    scope
   --> rustnum/src/linear_algebra/operations/decomposition/lu.rs:151:86
    |
151 |         return        (Arc::try_unwrap(l).unwrap().into_inner().unwrap(),Arc::try_unwrap(u).unwrap().into_inner().unwrap());
    |                                                                                      ^^^^^^
    |
= note: the method `unwrap` exists but the following trait bounds were not satisfied:
        `std::sync::Arc<std::sync::Mutex<linear_algebra::upper_triangular::UpperTriangular>> : std::fmt::Debug`

I understand nothing ! x(

But this work :

fn test_probleme() -> f64 
{
    let mut a = Arc::new(Mutex::new(5f64));

    return Arc::try_unwrap(a).unwrap().into_inner().unwrap();
}

I suspect problem is in the structure of my library...

Thank you, but to do this I need a mutable reference of my value, no ? Get mutable reference of the value is the same problem in my opinion...

You can use Mutex::lock to get a mutable reference to the value:

fn f<T: Default>(x: Arc<Mutex<T>>) -> T {
    std::mem::take(&mut x.lock().unwrap())
}

(Playground)

Result::unwrap prints the error value when it fails. The type must implement Debug so it can be printed here if you use unwrap.

You can fix this error by adding #[derive(Debug)] to the type.

Good idea, but I have this error :

error[E0658]: use of unstable library feature 'mem_take'
   --> rustnum/src/linear_algebra/operations/decomposition/lu.rs:152:57
|
152 |         return (std::mem::take(&mut *l.lock().unwrap()),std::mem::take(&mut *u.lock().unwrap()));
|                                                         ^^^^^^^^^^^^^^
|
    = note: for more information, see https://github.com/rust-lang/rust/issues/61129

It seem this is for unstable version of rust.

std::mem::take is available in Rust 1.40 and later. If you are using an old version of Rust, you can write this instead:

std::mem::replace(&mut *l.lock().unwrap(), Default::default())

That's work by adding the Debug trait ! Thank you verry much ! (and thank you for the other solution, this is interesting ! :smiley:)

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