Lifetime when moving ownership to thread

I am getting the parameter type M may not live long enough error.
Not sure how to interpret it. On one hand, Rust does not know when thread is going to be terminated, and to be safe, considers its life time 'static. Closure which captures context variables, has life time... well, I am confused. It is marked as move, so as long as params are Send, lifetime should not matter, because thread is now owner of any variable being used in closure. Compiler says "so that the type [closure@... will meet its required lifetime bounds" but I have no idea what its lifetime bounds are.

use std::thread;
use std::sync::mpsc;

trait ToMessage : Send {
    fn value(&self) -> Vec<u8>;
}

fn test<M>() where M: ToMessage {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move ||{
        let m: M = rx.recv().unwrap();
    });
}

fn main() {}
error[E0310]: the parameter type `M` may not live long enough
  --> src/main.rs:10:5
   |
8  | fn test<M>() where M: ToMessage {
   |         - help: consider adding an explicit lifetime bound `M: 'static`...
9  |     let (tx, rx) = mpsc::channel();
10 |     thread::spawn(move ||{
   |     ^^^^^^^^^^^^^
   |
note: ...so that the type `[closure@src/main.rs:10:19: 12:6 rx:std::sync::mpsc::Receiver<M>]` will meet its required lifetime bounds
  --> src/main.rs:10:5
   |
10 |     thread::spawn(move ||{
   |     ^^^^^^^^^^^^^
1 Like

The closure is only 'static if everything it captures is 'static. Using move is a good start, but the values you captured with move still have to be 'static too. You have rx: Receiver<M>, which can only be 'static if the type M is too. You can add this bound where M: ToMessage + 'static.

If this were not enforced, then it would be possible to smuggle a borrowed M value to the 'static thread, where its lifetime would not be properly respected.

3 Likes

You can check out my blog on closures to see how they are desugarred, this should give a better understanding of how it works

4 Likes

@cuviper Ah, I think I understand what I am missing now. I never could figure out, what declaration where T : X means, could T be X or &X. Because if i remember, you can declare where T : &X. I need to re-read this piece of documentation. With M being possible a reference, I do understand now compiler's concern.

Thanks Krishna, I glanced over your post and it looks very well written and address my exact scenario in the final paragraphs. I'll take more time in the evening to read it carefully.

@RustyYato I had time to read your blog more carefully and I want to thank you once again. I wish rust book was written in this style. It turns out, to be very simple concept and problem is in documentation and not in rust complexity at al. I looked at closure chapter in rust book and it is hopeless. Please blog more!

3 Likes

Thank you!

1 Like