Home > OS >  Returning all moved values from thread back to original context in Rust
Returning all moved values from thread back to original context in Rust

Time:07-12

As far as I learned, in Rust to get access to fields from context to the spawned thread I need to move them (not only borrow them) which is ok. Let's consider example:

use std::thread;

fn main() {
    let v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];

    let handle = thread::spawn(move || {
        println!("{:?}", v1);
        println!("{:?}", v2);
        (v1, v2)
    });

    let (v1, v2) = handle.join().unwrap();

    println!("{:?}", v1);
    println!("{:?}", v2);
}

Here v1 and v2 are moved to thread and if I want to use them again in main thread I need to return them from thread and assign them again using handle.join() (which waits until thread is done which is also nice).

My question: is it possible to somehow return all moved values back to their original fields? I can imagine that there is much more than just two fields I would move and writing down all of them to return and assign them again would look obscure.

CodePudding user response:

If you need to move a lot of variables together, the obvious way to do that is with a struct.

use std::thread;

struct ManyFields {
    v1: Vec<i32>,
    v2: Vec<i32>,
    // ...and many others...
}

fn main() {
    let fields = ManyFields {
        v1: vec![1, 2, 3],
        v2: vec![4, 5, 6],
    };

    let handle = thread::spawn(move || {
        println!("{:?}", fields.v1);
        println!("{:?}", fields.v2);
        fields
    });

    let fields = handle.join().unwrap();

    println!("{:?}", fields.v1);
    println!("{:?}", fields.v2);
    // and many others...
}

Depending on exactly why you needed the thread to take ownership, you may be able to avoid that altogether using scoped threads. Scopes introduce an explicit lifetime in which a thread is guaranteed to finish, allowing you borrow values as long as they outlive the scope.

use crossbeam::scope;

fn main() {
    let v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];

    scope(|scope| {
        scope.spawn(|_| {
            println!("{:?}", v1);
            println!("{:?}", v2);
        });
    })
    .unwrap();

    println!("{:?}", v1);
    println!("{:?}", v2);
}

From rust 1.63 you will be able to do this without a third party crate, as it will be part of std.

  • Related