Search code examples
multithreadingrustcrossbeam

I dont understand this lifetime error : spawining threads inside a struct function


Not much to explain. I don't understand what is even having the lifetime designated 1 and 2 by the compiler error message.

All posts I have checked so far just say use crossbeam for scopped threads, but this hasn't fixed my issue at all and I dont think I even understand the finer issue here.

Any help is appreciated.

use crossbeam_utils::thread;

struct TestStruct {
    s: f64,
}

impl TestStruct {
    fn new() -> Self {
        Self {
            s: -1.,
        }
    }
    fn fubar(&'static self) -> f64 {
        let thread_return_value = thread::scope(|scope|
            // lifetime may not live long enough
            // returning this value requires that `'1` must outlive `'2`
            // Question: what are the two lifetimes even of? I am probably just
            // a noob here.
            scope.spawn(move |_| { // same error with or without move
                // I have found that it doesnt matter what I put in this scope,
                // but the following is the closest to what I have in my actual
                // code.
                let mut psum = 0.;
                for _ in 0..10 { psum += self.s; }
                psum
            })
        ).unwrap();
        // do anything with thread_return_value

        return 0.; // just so its explicitly not the problem here, return 0.
    }
}


fn main() {
    let test_item = TestStruct::new();
    // rustcE0597
    let stored_value = test_item.fubar();
    println!("{}", &stored_value);
    return;
}

Edit after marking for correct answer, working minimal example:

#![feature(let_chains)]
use crossbeam_utils::thread;


struct TestStruct {
    s: f64,
}

impl TestStruct {
    fn new() -> Self {
        Self {
            s: -1.,
        }
    }

    fn fubar(&self) -> f64 {
        let thread_return_value = thread::scope(|scope| {
            let th = scope.spawn(move |_| {
                let mut psum = 0.;
                for _ in 0..10 { psum += self.s; }
                psum
            });
            let psum = th.join().unwrap();
            psum
        }
        ).unwrap();
        return thread_return_value;
    }
}


fn main() {
    let test_item = TestStruct::new();
    // rustcE0597
    let stored_value = test_item.fubar();
    println!("{}", &stored_value);
    return;
}

Solution

  • The most obvious problem in your code is the &'static self lifetime. If you do so, you will only be able to call this function with static (that is, global) values of this type. So just remove that 'static and write &self.

    Then the real problem is because you are trying to return your scoped thread handle from the crossbeam::scoped, the value returned by scope.spawn(), and that is not allowed. That is why they are called scoped threads: they are limited to the enclosing scope.

    Remember that in Rust, when a block ends without a ; the value of the last expression is returned as the value of the block itself.

    You probably want to return the psum. If so you need to wait for the handle to finish:

        fn fubar(& self) -> f64 {
            let thread_return_value = thread::scope(|scope| {
                let th = scope.spawn(move |_| {
                    let mut psum = 0.;
                    for _ in 0..10 { psum += self.s; }
                    psum
                }); // <--- here, add a ;
                let psum = th.join().unwrap(); //get the inner result
                psum //forward it to the outer scope
            }).unwrap();
            return 0.;
        }