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


#1

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: http://is.gd/z8oHo3

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

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


#3

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

http://is.gd/2NSiWv

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


#4

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.


#5

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.


#6

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