1

I'm a newbie of concurrency. The context is I spawn a thread that using a method with a lifetime in a struct method. Then I got an error cannot infer an appropriate lifetime due to conflicting requirements

Here is a simplified example of my code.

use std::thread;
use std::time::Duration;

struct Printer{
    prefix: &'static str,
}

impl Printer {
    pub fn print(&self, text: String) {
        println!("{}: {}", self.prefix, text);
    }
    
    pub fn new(prefix: &'static str) -> Self {
        Printer {
            prefix: prefix
        }
    }
}

struct Foo<'a> {
    printer: &'a Printer
}

impl<'a> Foo<'a> {
    fn pop(&self) {
        thread::spawn(|| {
            self.printer.print(String::from("pop"));
        });
    }
    
    pub fn new(printer: &'a Printer) -> Self {
        Foo {
            printer: printer
        }
    }
}

fn main() {
    let printer = Printer::new("freaking");
    printer.print(String::from("hell"));
    let foo = Foo::new(&printer);
    
    foo.pop();
}
Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:28:23
   |
28 |           thread::spawn(|| {
   |  _______________________^
29 | |             self.printer.print(String::from("pop"));
30 | |         });
   | |_________^
   |
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 26:6...
  --> src/main.rs:26:6
   |
26 | impl<'a> Foo<'a> {
   |      ^^
note: ...so that the types are compatible
  --> src/main.rs:28:23
   |
28 |           thread::spawn(|| {
   |  _______________________^
29 | |             self.printer.print(String::from("pop"));
30 | |         });
   | |_________^
   = note: expected `&&Foo<'_>`
              found `&&Foo<'a>`
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/main.rs:28:23: 30:10 self:&&Foo<'_>]` will meet its required lifetime bounds
  --> src/main.rs:28:9
   |
28 |         thread::spawn(|| {
   |         ^^^^^^^^^^^^^

error: aborting due to previous error

How could I avoid this error? Is it an anti-pattern for concurrency?

WendellLiu
  • 307
  • 5
  • 12
  • 1
    The closure you are passing to `thread::spawn` is capturing `self` by reference. There is no guarantee that `self` will outlive the thread, which is why Rust only allows static references to be sent to threads. The solution very much depends on precisely what you want to achieve. – user4815162342 Aug 20 '20 at 14:33
  • @user4815162342, what I want to achieve is that I store a singleton(Printer here) in a struct(Foo here) and wrap the method of Printer to a new method which is belonged by Foo. I believe it's a general requirement but I don't know how to implement it in a good pattern. – WendellLiu Aug 20 '20 at 14:36
  • If `Printer` is a singleton, why does `Foo` need to hold a reference to it? Do you understand what a singleton means? – user4815162342 Aug 20 '20 at 14:39
  • Okay, my bad. Let's call it an instance. – WendellLiu Aug 20 '20 at 14:44
  • 1
    If you want to use `Printer` from multiple threads, you'll probably need to make it an `Arc` instead of a reference. `Arc` is a pointer, but the object it points to includes a reference count, which makes `Arc` suitable for shared ownership, where the object is destroyed when the last owner goes out of scope. Then you can send the pointer to the thread by "cloning" it (which just bumps a reference count) - as shown [here](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b35fead9a160b964c971010b5c9ab831). – user4815162342 Aug 20 '20 at 14:46
  • 1
    Does this answer your question? [How can I pass a reference to a stack variable to a thread?](https://stackoverflow.com/questions/32750829/how-can-i-pass-a-reference-to-a-stack-variable-to-a-thread) – trent Aug 20 '20 at 15:01
  • hey @trentcl, it is. Both answers are helpful to me and since I try to build my own threadpool from scratch, in my project, I prefer the first one. Thanks anyway. – WendellLiu Aug 20 '20 at 15:45
  • @user4815162342, thanks for helping. I can choose your answer if you need more reputation here. – WendellLiu Aug 20 '20 at 15:46
  • More reputation is always nice :) but the question should probably be closed as a dupe because my comment doesn't bring anything new compared to a bunch of existing answers that explain how to use an `Arc` to enable sending something to a thread. – user4815162342 Aug 20 '20 at 15:49
  • Here's a [Q&A that demonstrates `Arc`](/q/52437174/3650362). And [here's another](/q/30862646/3650362). @user4815162342 is right, it's best to redirect people to the existing answers if possible (unless there is something unique about this question so that the others don't apply). (This comment is not a criticism, just linking the other questions for reference) – trent Aug 20 '20 at 15:58

0 Answers0