Ronin Goda
Ronin Goda

Reputation: 234

How to solve "lifetime must be valid for the static lifetime" in calling thread methods

I am a Rust beginner and I can’t get the following code to compile. I know this problem might be not new, tried searching all over the place but couldn't find a proper answer to the below problem.

Basically i m trying to call methods from thread, and also using different structs for sending and receiving objects between the threads.

use std::{thread, time};

struct SenderStruct;

impl SenderStruct {
    fn send(&self, sndr: Sender<(Option<String>)>) {
        let count = 0;
        loop {
            sndr.send(Some(String::from("Hello"))).unwrap();
            thread::sleep(time::Duration::from_millis(1000));
            count = count + 1;

            if count == 50 {
                break;
            }
        }

        sndr.send(None);
    }
}

struct ReceiveStruct;

impl ReceiveStruct {
    fn receive(&self, rec: Receiver<Option<String>>) {
        loop {
            let recv_out = rec.recv().unwrap();
            match recv_out {
                Some(some_str) => println!("{}", some_str),
                None => break,
            }
        }
    }
}

struct SendReceiveStruct {
    m_ss: SenderStruct,
    m_sos: ReceiveStruct,
    m_recv_hndlr: Option<thread::JoinHandle<()>>,
}

impl SendReceiveStruct {
    fn new() -> Self {
        SendReceiveStruct {
            m_ss: SenderStruct {},
            m_sos: ReceiveStruct {},
            m_recv_hndlr: None,
        }
    }

    fn start(&mut self) {
        let (tx, rx): (Sender<(Option<String>)>, Receiver<Option<String>>) = channel();

        thread::spawn(move || self.m_ss.send(tx));
        self.m_recv_hndlr = Some(thread::spawn(move || self.m_sos.receive(rx)));
    }

    fn wait_for_recevier(&mut self) {
        self.m_recv_hndlr.unwrap().join();
    }
}
fn main() {
    println!("Hello, world!");

    let mut ubs = SendReceiveStruct::new();
    ubs.start();

    ubs.wait_for_recevier();
}

But i m getting lifetime issues all over the place

$ cargo build
   Compiling threads v0.1.0 (/root/learn-rust/threads)
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:55:23
   |
55 |         thread::spawn(move || self.m_ss.send(tx));
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 52:5...
  --> src/main.rs:52:5
   |
52 | /     fn start(&mut self) {
53 | |         let (tx, rx): (Sender<(Option<String>)>, Receiver<Option<String>>) = channel();
54 | |
55 | |         thread::spawn(move || self.m_ss.send(tx));
56 | |         self.m_recv_hndlr = Some(thread::spawn(move || self.m_sos.receive(rx)));
57 | |     }
   | |_____^
   = note: ...so that the types are compatible:
           expected &mut SendReceiveStruct
              found &mut SendReceiveStruct
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/main.rs:55:23: 55:49 self:&mut SendReceiveStruct, tx:std::sync::mpsc::Sender<std::option::Option<std::string::String>>]` will meet its required lifetime bounds
  --> src/main.rs:55:9
   |
55 |         thread::spawn(move || self.m_ss.send(tx));

Any pointers (or other references) would really help, and also any other possible approaches for the above problem ?

Upvotes: 0

Views: 3555

Answers (1)

edwardw
edwardw

Reputation: 13942

If you examine the signature of std::thread::spawn:

pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
    F: FnOnce() -> T,
    F: Send + 'static,
    T: Send + 'static,

and its documentation closely:

The 'static constraint means that the closure and its return value must have a lifetime of the whole program execution. The reason for this is that threads can detach and outlive the lifetime they have been created in.

However, the &mut self value closure closes over may not live long enough. One way to overcome that is to clone the value the closure actually uses:

#[derive(Clone)]
struct SenderStruct;

#[derive(Clone)]
struct ReceiveStruct;

impl SendReceiveStruct {
    fn start(&mut self) {
        let (tx, rx): (Sender<Option<String>>, Receiver<Option<String>>) = channel();

        thread::spawn({
            let ss = self.m_ss.clone();
            move || ss.send(tx)
        });
        self.m_recv_hndlr = Some(thread::spawn({
            let sos = self.m_sos.clone();
            move || sos.receive(rx)
        }));
    }

    fn wait_for_recevier(&mut self) {
        self.m_recv_hndlr.take().unwrap().join();
    }
}

Except for several other minor issues, your code now compiles.

Upvotes: 4

Related Questions