3

Here's a toy example of my problem:

use std::sync::{Arc, Mutex};

fn operate_in_chunks(vec: &mut Vec<f32>) {
    let chunk_size = 10;
    let mutex_vec: Arc<Mutex<&mut Vec<f32>>> = Arc::new(Mutex::new(vec));

    let handles = Vec::new();

    for chunk in 0..vec.len() / chunk_size {
        handles.push(std::thread::spawn(move || {
            operate(mutex_vec, chunk);
        }));
    }

    for i in 0..handles.len() {
        handles[i].join().unwrap();
    }
}

fn operate(mutex_vec: Arc<Mutex<&mut Vec<f32>>>, chunk: usize) {}

I'd like to do some work on the passed-in struct, split among a number of threads, and then join them all back together before returning.

The error I get says:

error[E0621]: explicit lifetime required in the type of `vec`
  --> src/lib.rs:10:22
   |
3  | fn operate_in_chunks(vec: &mut Vec<f32>) {
   |                           ------------- help: add explicit lifetime `'static` to the type of `vec`: `&'static mut std::vec::Vec<f32>`
...
10 |         handles.push(std::thread::spawn(move || {
   |                      ^^^^^^^^^^^^^^^^^^ lifetime `'static` required

I understand what it's complaining about: if the threads may have a 'static lifetime, and they reference vec, vec must have a 'static lifetime. However, my use-case should in theory be possible: I want to guarantee that the threads don't have a 'static lifetime, as they're all joined before the function returns, in which case I shouldn't need a 'static' lifetime onvec`.

Does Rust have a way of articulating this - unifying the lifetime of the threads with the lifetime of vec - or are all threads always 'static no matter what?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
brundolf
  • 1,170
  • 1
  • 9
  • 18
  • 1
    [Crossbeam](https://docs.rs/crossbeam/0.3.0/crossbeam/struct.Scope.html) has a concept of scoped threads, which allow you to use non-static lifetimes. – Alex Huszagh Aug 25 '19 at 03:47
  • 1
    Scoped threads got removed like 2 years ago from Rust, so there is no way in Rust std to use non-static lifetimes: https://www.reddit.com/r/rust/comments/57c5uq/what_happened_to_threadscoped/ – Alex Huszagh Aug 25 '19 at 03:54
  • What about if the operate_in_chunks method panics before calling join()? That would cause the reference to be dropped too early. – SOFe Aug 25 '19 at 04:11
  • 1
    Wow, that thread and ones linked from it really paint this as an epic (and ongoing) saga. I think that's the closest possible thing to an answer, if you want to post it as such. – brundolf Aug 25 '19 at 04:11

1 Answers1

4

Rust actually used to allow scoped threads, which allow non-static lifetimes for any data passed. However, the API was found to be unsound and they were removed around two years ago. Fortunately, crossbeam, a crate, implements scoped threads with a different API allowing you to use this functionality safely. A sample from crossbeam's documentation is here:

let array = [1, 2, 3];

crossbeam::scope(|scope| {
    for i in &array {
        scope.spawn(move || {
            println!("element: {}", i);
        });
    }
});
trent
  • 25,033
  • 7
  • 51
  • 90
Alex Huszagh
  • 13,272
  • 3
  • 39
  • 67