Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
460 views
in Technique[技术] by (71.8m points)

rust - Why can't I put a borrowed value behind a Mutex and pass it to another thread?

I'm trying to put a borrowed value behind a Mutex but I'm having trouble with the borrow checker. Here's a simplified code that demonstrate the problem I encounter:

use std::{
    marker::PhantomData,
    sync::{Arc, Mutex},
};

struct Test<'a> {
    d: PhantomData<Mutex<&'a u8>>,
}

impl<'a> Test<'a> {
    pub fn new() -> Self {
        Test { d: PhantomData }
    }
    pub fn test(&'a self) {}
}

fn main() {
    let t = Arc::new(Test::new());
    let t2 = t.clone();
    std::thread::spawn(move || {
        t2.test();
    });
}

This fails to compile with the following error

error[E0597]: `t2` does not live long enough
  --> src/main.rs:21:9
   |
19 |     let t2 = t.clone();
   |         -- lifetime `'1` appears in the type of `t2`
20 |     std::thread::spawn(move || {
21 |         t2.test();
   |         ^^-------
   |         |
   |         borrowed value does not live long enough
   |         argument requires that `t2` is borrowed for `'1`
22 |     });
   |     - `t2` dropped here while still borrowed

I guess the compiler thinks t2 might be borrowed to somewhere else when calling test(). It seems if I modify the type of the d field in struct Test to anything excluding Mutex, such as d: Option<&'a u8>, it works fine. What is so special about Mutex since it's just a wrapper around an UnsafeCell?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

What is so special about Mutex since it's just a wrapper around an UnsafeCell?

The difference is variance.

&'a T is covariant in the lifetime 'a: You can coerce an immutable reference with a longer lifetime to one with a strictly shorter lifetime, because it is always safe to pass &'long T where &'short T is expected. This is why the code compiles without the UnsafeCell.

But UnsafeCell<&'a T> is invariant in 'a because it has interior mutability: If you could pass UnsafeCell<&'long T> to code that takes UnsafeCell<&'short T>, that code could write a short-lived reference into your long-lived cell. So it is not safe to coerce an UnsafeCell to have a different lifetime.

(The same is true for any type that lets you mutate the reference it contains, e.g. Mutex<&'a T> or &mut &'a T.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...