Rust中使用线程时self参数的生命周期

4

我正在学习Rust,有以下代码:

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

pub struct MyText {
    my_text: Mutex<Vec<String>>,
}

pub trait MyTextOptions {
    fn add(&self, t: String);
}

impl MyTextOptions for MyText {
    fn add(&self, text: String) {
        let int_text = Arc::new(self);
        let put_into_my_text = spawn(move || {
            let mut text_feed = int_text.my_text.lock().unwrap();
            text_feed.push(text)
        });
        put_into_my_text.join();
    }
}

当我尝试运行它时,出现以下错误提示:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src\buffer.rs:37:33
   |
37 |         let int_text = Arc::new(self);
   |                                 ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 36:5...
  --> src\buffer.rs:36:5
   |
36 | /     fn add(&self, text: String) {
37 | |         let int_text = Arc::new(self);
38 | |         let put_into_my_text = spawn(move || {
39 | |             let mut text_feed = int_text.my_text.lock().unwrap();
...  |
42 | |         put_into_my_text.join();
43 | |     }
   | |_____^
   = note: ...so that the expression is assignable:
           expected &buffer::MyText
              found &buffer::MyText
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src\buffer.rs:38:38: 41:10 int_text:std::sync::Arc<&buffer::MyText>, text:std::string::String]` will meet its required lifetime bounds
  --> src\buffer.rs:38:32
   |
38 |         let put_into_my_text = spawn(move || {
   |

在使用线程时,我似乎无法理解Rust中变量的生命周期。无论我如何处理这个函数,我仍然会得到这种类型的错误。


基本上,您在该函数的持续时间内借用了 self。线程可以超出该函数的生命周期。 - jhpratt
1个回答

8
通过thread::spawn创建的线程理论上可以超出其父线程的生命周期。如果子线程引用了来自父线程的数据,当父线程停止时,这些引用将失效(无效)。这在给定给thread::spawn的闭包上表现为一个 'static 的约束。你在同一函数中使用join线程并不能被编译器理解,因此这个限制仍然存在。
你已经尝试使用Arc(可能是为了解决这个问题),但你正在创建一个selfArc引用。所以你只是把一个引用放到了Arc中。该值不满足'static的约束,这就是为什么你会得到一个错误。
有多种方法可以解决这个问题,许多方法取决于您项目的总体架构。其中最简单的一种方式是使用crossbeamscoped(或者具体地说,crossbeam_utils):
use crossbeam_utils::thread;

impl MyTextOptions for MyText {
    fn add(&self, text: String) {
        thread::scope(|s| {
            s.spawn(|_| {
                let mut text_feed = self.my_text.lock().unwrap();
                text_feed.push(text)
            });
        }).unwrap();
    }
}

这是一个精巧的帮助函数,它可以通过确保子线程结束之前父线程结束来借用父作用域的值。

另一种解决方案是将 MyText 值放入 Arc 中(特别是:按值而不是按引用)。然后你可以克隆这个 Arc 多次并将其发送到一个新线程中。但是这意味着你无法使用那些以 &self 为接收器的方法,而必须找到另一种解决方式。


谢谢,但是当我像这样实现它时,我会得到以下错误: | ^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>```. 顺便说一下,我仍然在使用 ``` let int_text = Arc::new(self.clone()); - TalG
我再也不会用这个解决方案遇到上述错误了。 - TalG
为什么编译器无法理解您在同一函数中加入线程的事实呢? - Saddle Point

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接