Passing two objects, where one holds reference to another into a thread

Hello, I have two variables where the second one requires the fist one to outlive it. I need to move both of them into a thread, but the compiler is complaining that the first one doesn't live long enough. Here is the code:

use std::thread;

trait Facade : Sync { fn add(&self)->u32; }

struct RoutingNode<'a> { facade: &'a (Facade + 'a) }

impl<'a> RoutingNode<'a> {
  fn new(facade: &'a Facade) -> RoutingNode<'a> {
    RoutingNode { facade: facade }
  }
}

fn main() {
  struct MyFacade;
  
  impl Facade for MyFacade {
    fn add(&self)->u32 { 999u32 }
  }
  
  let facade = MyFacade;
  let routing = RoutingNode::new(&facade);
  
  let t = thread::spawn(move|| {
    let f = facade;
    let r = routing;
  });

  t.join();
}

Here is the code too, for easier testing: Rust Playground

And the error:

<anon>:25:35: 25:41 error: `facade` does not live long enough
<anon>:25   let routing = RoutingNode::new(&facade);
                                            ^~~~~~
note: reference must be valid for the static lifetime...
<anon>:24:24: 33:2 note: ...but borrowed value is only valid for the block suffix following statement 2 at 24:23

I can see the problem is that I somehow need to tell rust explicitly that the facade will outlive routing object. Just have no clue how.

2 Likes

I believe, if you move facade into the closure, the original reference becomes invalid indeed.
You might need to put it in a box?

1 Like

Thanks, it makes sense, but then I'm having problem getting the Facade trait out of the Box.

(sorry if stupid question, I'm very new to rust)

It's not that simple I'm afraid. I'm not sure how exactly you want to use the facade. One way is this

use std::thread;

trait Facade : Send { fn add(&self)->u32; }

struct RoutingNode { facade: Box<Facade> }

impl RoutingNode {
  fn new(facade: Box<Facade>) -> RoutingNode {
    RoutingNode { facade: facade }
  }
  fn into_inner(self) -> Box<Facade> {
    self.facade
  }
}

fn main() {
  struct MyFacade;
  unsafe impl Send for MyFacade {}
  
  impl Facade for MyFacade {
    fn add(&self)->u32 { 999u32 }
  }
  
  let facade = Box::new(MyFacade);
  let routing = RoutingNode::new(facade);
  
  let t = thread::spawn(move|| {
    let r = routing;
    let f = r.into_inner();
    // f outlives r
  });
}

If you want it to be shared between threads, you might need Arc.

Box<Facade> is a trait object as well as a &Facade.

2 Likes

I was hoping for a solution where I wouldn't need to change the RoutingNode and Facade structures. I mean, I can change them since they are in our code base, but if they weren't, would I be stuck? What adds to the problem, is that I can't create the routing object inside the thread because I need to use it before it goes to the thread. Fortunately, I don't need to then share those objects between threads (just move it once from the main thread to the other one), so no need for Arc.

1 Like

I asked this question on Stack Overflow too, got some additional solutions:

http://stackoverflow.com/questions/29526058/passing-two-objects-where-one-holds-a-reference-to-another-into-a-thread

1 Like