porton
porton

Reputation: 5827

How to pass immutable parameters to a thread? (about lifetimes)

Let thread state consists of immutable parameters Params and the rest of the (mutable) state State.

I am trying to mock spawning a thread that does something being controlled by parameters Params:

use std::thread;

struct Params {
    x: i32,
}

struct State<'a> {
    params: &'a Params,
    y: i32,
}

impl<'a> State<'a> {
    fn new(params: &Params) -> State {
        State {
            params,
            y: 0,
        }
    }
    fn start(&mut self) -> thread::JoinHandle<()> {
        let params = self.params.clone();
        thread::spawn(move || { params; /* ... */ })
    }
}

But this does not work:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> test.rs:20:34
   |
20 |         let params = self.params.clone();
   |                                  ^^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 12:6...
  --> test.rs:12:6
   |
12 | impl<'a> State<'a> {
   |      ^^
note: ...so that the types are compatible
  --> test.rs:20:34
   |
20 |         let params = self.params.clone();
   |                                  ^^^^^
   = note: expected  `&&Params`
              found  `&&'a Params`
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[[email protected]:21:23: 21:42 params:&Params]` will meet its required lifetime bounds
  --> test.rs:21:9
   |
21 |         thread::spawn(move || { params; /* ... */ })
   |         ^^^^^^^^^^^^^

I understand why it does not work: The thread could run indefinitely long, and the params could be destroyed before it is terminated. That's clearly an error.

Now explain what is the proper way to make params long at least as long as the thread. In other words, help to correct the above code. What should I do with lifetimes?

Upvotes: 0

Views: 74

Answers (1)

mcarton
mcarton

Reputation: 30111

You got the right idea with using clone and a move lambda, but you forgot one detail: Params isn't Clone! Therefore the compiler did the best it could when it saw self.params.clone() and cloned… the reference.

That's why the error messages have two & here:

   = note: expected  `&&Params`
              found  `&&'a Params`

Your issue is solved by using #[derive(Clone)] struct Params { /* … */ }.

Upvotes: 1

Related Questions