1

In the code below, I had to add the 'static lifetime to the s parameter, in order to get rid of this error:

error[E0621]: explicit lifetime required in the type of `s`
 --> src/main.rs:4:14
  |
3 | fn run(s: &str) {
  |           ---- help: add explicit lifetime `'static` to the type of `s`: `&'static str`
4 |     let h1 = thread::spawn(move || {
  |              ^^^^^^^^^^^^^ lifetime `'static` required
use std::thread;

fn run(s: &'static str) {
    let h1 = thread::spawn(move || {
        println!("{} from thread 1", s);
    });
    let h2 = thread::spawn(move || {
        println!("{} from thread 2", s);
    });

    h1.join().unwrap();
    h2.join().unwrap();
}

fn main() {
    run("hi");
}

I can understand that the compiler is unable to ensure that the spawned threads are all finished at the end of the function run(); however in pratice, this is the case: the threads are both joined before the function ends, without condition. So in this case, I know that I don't need a 'static lifetime.

So what I would like is to implement the same function, but without the 'static requirement:

fn run(s: &str) {
    // Spawn some threads which have read access to the variable 's'
    // Join all the threads at the end of the function
}

How can I do that?

yolenoyer
  • 8,797
  • 2
  • 27
  • 61
  • Partially yes, thank you. I already saw references to crossbeam, I just tested it and it is working. But I was also wondering how to implement it without an external crate. I will look at the crossbeam code to understand it more deeply. – yolenoyer Aug 15 '20 at 06:07
  • Without crossbeam you could make two copies of the string and pass them to threads. Or you could make a single copy, wrap it in an [`Arc`](https://doc.rust-lang.org/beta/std/sync/struct.Arc.html) (Rust's thread-safe reference-counted smart pointer) and send the Arcs to the threads. Either way, without crossbeam you _will_ need at least one copy because, barring the use of a static string, the borrow checker won't be able to prove that none of the threads outlive `run()`, despite it being obvious (barring panics) to a human reader. – user4815162342 Aug 15 '20 at 12:19
  • Studying crossbeam's source might give you the wrong idea because crossbeam internally uses `unsafe` in a way that is sound given the public API it exposes. In other words, it uses `unsafe` so you don't have to, which is why you can't (more precisely, you don't _need to_!) use their approach in your own programs. – user4815162342 Aug 15 '20 at 12:23
  • Thank you @user4815162342 for your comments, they are really useful to me. But maybe I misunderstood one point: you wrote: "you don't need to [use crossbeam approach]". But as you wrote earlier, without crossbeam or `unsafe`, I need at least one copy, which looks unacceptable if the only goal is to satisfy the compiler. So, why not using the `unsafe` technique (which I first have to understand)? Do you mean: "Don't reinvent the wheel" ? – yolenoyer Aug 15 '20 at 15:53
  • Sorry in advance for misunderstandings – yolenoyer Aug 15 '20 at 15:54
  • Yes, I meant it in the "don't reinvent the wheel" sense, especially when the wheel involves unsafe. If you were required not to use crossbeam, I'm sure you could find a different way to implement this without copying - e.g. by modifying the function to receive an `Arc` or by simply making the required copy. I don't see the copy as necessarily _unacceptable_ because that depends on what you're doing and how large the string is. Here you are creating two threads, which is several orders of magnitude more expensive than cloning a string. – user4815162342 Aug 15 '20 at 17:08
  • Ok, now it's perfectly clear to me! Thank you again for your comments – yolenoyer Aug 16 '20 at 06:05

1 Answers1

1

Here is how this can be solved by using the crossbeam crate:

use crossbeam::thread;

fn run(s: &str) {
    thread::scope(|scope| {
        let h1 = scope.spawn(move |_| {
            println!("{} from thread 1", s);
        });
        let h2 = scope.spawn(move |_| {
            println!("{} from thread 2", s);
        });
    }).unwrap();
}

fn main() {
    run("hi");
}
yolenoyer
  • 8,797
  • 2
  • 27
  • 61