Iterate on vector then use values in thread

#1

Hello,

I’m trying to use a struct attribute vector in a thread, with following code:

use std::thread;

fn main() {
    let mut handles = Vec::new();

    struct Foo {
        bar: Vec<Vec<u32>>,
    }
    let mut bar: Vec<Vec<u32>> = Vec::new();
    let mut baz: Vec<u32> = Vec::new();
    baz.push(42);
    bar.push(baz);

    let foo = Foo{bar};

    for bar2 in foo.bar.iter() {
        for ii in bar2.iter() {
            handles.push(thread::spawn(move || {
                println!("{:?}{}", bar2, ii);
            }));
        }
    }

    for handle in handles {
        let _ = handle.join();
    }

    println!("ok")
}

But foo.bar borrowed value does not live long enough:

error[E0597]: `foo.bar` does not live long enough
  --> src/main.rs:16:17
   |
16 |     for bar2 in foo.bar.iter() {
   |                 ^^^^^^^-------
   |                 |
   |                 borrowed value does not live long enough
   |                 argument requires that `foo.bar` is borrowed for `'static`
...
29 | }
   | - `foo.bar` dropped here while still borrowed

error: aborting due to previous error

Wat is the correct way to iterate over foo.bar ?

#2

Rust doesn’t care about main() being special, and expects the threads to live longer than main(). So whatever you create in main is not good. Stuff you send to threads has to live forever.

In practice, don’t use thread::spawn for such things. Use the rayon crate to iterate in parallel, with more scoped lifetimes, proper threadpool, etc.

As for the exercise, your move doesn’t do anything, because iter() iterates by temporary reference, so the owned original stays where it was (things can’t be moved while a borrow of them exists). So you should change .iter() to .into_iter() or .drain(..) that “consume” collections and give you owned values that you can send to threads.

4 Likes
#3

I believe crossbeam::thread::scoped from crossbeam would also solve your problem, if you want to continue using threads explicitly.

1 Like
#4

Hello,

Thank’s for your suggests. I will test these two solutions (in my original case, i would like receive data from my threads, so i think i will use crossbeam::thread::scoped in my final code).