首页 > 解决方案 > 为什么我不能将借来的值放在 Mutex 后面并将其传递给另一个线程?

问题描述

我试图将借来的值放在 a 后面,Mutex但借用检查器遇到问题。这是一个简化的代码,演示了我遇到的问题:

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();
    });
}

这无法编译并出现以下错误

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

我猜编译器认为t2在调用test(). 似乎如果我将d字段的类型修改为struct Test不包括 的任何内容Mutex,例如d: Option<&'a u8>,它就可以正常工作。Mutex 有什么特别之处,因为它只是一个UnsafeCell?

标签: rustmutex

解决方案


Mutex 有什么特别之处,因为它只是一个UnsafeCell?

差异是方差

&'a T在生命周期中是协变'a的:您可以将具有较长生命周期的不可变引用强制转换为具有严格较短生命周期的引用,因为通过预期的&'long T地方总是安全的。&'short T这就是为什么代码在没有UnsafeCell.

但是它UnsafeCell<&'a T>不变的,'a因为它具有内部可变性:如果您可以传递UnsafeCell<&'long T>给需要的代码UnsafeCell<&'short T>,那么该代码可以将短期引用写入您的长期单元格。UnsafeCell所以强迫一个人过不同的生活是不安全的。

(任何允许你改变它包含的引用的类型也是如此,例如Mutex<&'a T>or &mut &'a T。)


推荐阅读