4

I'm in the process of learning Rust and I have this code:

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

When I try to run it I get:

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 || {
   |

I seem to fail to understand the lifetime of variables in rust when using threads. No matter what I do with this function I'm still getting this type of error.

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
TalG
  • 677
  • 1
  • 9
  • 26
  • Basically, you're borrowing `self` for the duration of that function. The thread can outlive that function. – jhpratt Aug 25 '19 at 08:18

1 Answers1

8

A thread spawned via thread::spawn can in theory outlive its parent thread. If the child thread could reference data from the parent thread, these reference would dangle (be invalid) when the parent thread stops. This is expressed as a 'static bound on the closure given to thread::spawn. The fact that you join the thread in the same function is not understood by the compiler, so the restriction still holds.

You already tried to use an Arc (presumably to get around this problem), but you are creating an Arc of self which is a reference already. So you are just putting a reference into an Arc. That value does not satisfy the 'static bound, that's why you are getting an error.

There are multiple ways to solve this problem, many depend on the overall architecture of your project. One of the easiest ways is to use scoped from crossbeam (or specifically, 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();
    }
}

This is a fancy helper function that actually lets you borrow values from the parent scope by ensuring the child thread ends before the parent thread does.

Another solution would be to put the MyText value into an Arc (notably: by value, not by reference). Then you can clone this Arc a bunch of times and send it to a new thread. But this means you cannot use methods that take &self as receiver, but you have to solve it in another way.

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
  • Thanks, but when I implement it like this I get: ```30 | impl MyTextOptions for MyText { | ^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>```. By the way I'm still using the ``` let int_text = Arc::new(self.clone()); ``` – TalG Aug 25 '19 at 16:22
  • I don't get the above error with this solution anymore. – TalG Aug 25 '19 at 20:17
  • `The fact that you join the thread in the same function is not understood by the compiler...` Why...? – Saddle Point Mar 10 '21 at 13:15