1

Given

fn greet(peeps: &str) {
    println!("Hello, {}", peeps);
}

I can do:

fn main() {
    let a = "World";
    thread::spawn(move || greet(a)).join().unwrap();
}

The compiler understands that the thread does not outlive the borrowed string, but this is merely a special case when the lifetime of the &str is known to be 'static. When I try to do the same with a function argument, it does not compile:

fn indirect(peeps: &str) {
    thread::spawn(move || greet(&peeps)).join().unwrap();
    // Does not compile, for fear that the thread may outlive peeps
}

However, to a human reader, it is obviously the case that the thread cannot outlive the borrowed string.

I have found two workarounds:

  1. Make a copy of the string, which can be moved into the thread:

    fn indirect(peeps: &str) {
        let peeps = peeps.to_string();
        thread::spawn(move || greet(&peeps)).join().unwrap();
    }
    
  2. or, make use of the famously deprecated thread::scoped:

    #![feature(scoped)]
    fn indirect_scoped(peeps: &str) {
        thread::scoped(move || greet(&peeps)).join();
    }
    

I don't want to specify 'static lifetime for the function parameter, I'd prefer not to make an unnecessary copy (workaround 1) and I'd prefer not to use deprecated features (workaround 2).

What should I do in this situation?

Magnus Hoff
  • 21,529
  • 9
  • 63
  • 82
  • It's not clear whether it would suit your use case, but `Arc` could also be a solution to this problem. It would require calling `to_string()` at some point given a `&str`, but then it could be shared across many threads without copying. – BurntSushi5 Nov 03 '15 at 12:25
  • "I'd prefer not to..." -- very understandable. I hope something like `scoped` will come back into the standard library. – sellibitze Nov 03 '15 at 18:55

1 Answers1

7

The approach with scoped() is the correct way when you want to pass borrowed data to child threads. While thread::scoped() itself is deprecated due to its unsoundness, an alternative sound APIs like crossbeam or scoped_threadpool provide a way to do this on stable Rust:

extern crate crossbeam;

fn indirect(peeps: &str) {
    crossbeam::scope(|scope| {
        scope.spawn(|| greet(peeps));
    });
}
Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296