-1

Can multiple threads share non-static data that is temporarily immutable (while the threads are running)?

For example, this code gives an error:

error[E0621]: explicit lifetime required in the type of v (line 4)

use std::sync::Arc;
use std::thread;

fn f(v : &Vec<i64>)
{
    let n = v.len();
    let a = Arc::new(v);
    let mut ts = Vec::new();

    for i in 0..n
    {
        let a_clone = a.clone();

        let t = thread::spawn(move ||
        {
            println!("thread {}, v[{}] = {}", i, i, a_clone[i]);
        });

        ts.push(t);
    }

    for t in ts
    {
        t.join().unwrap();
    }
}

fn g()
{
    let mut v : Vec<i64> = vec![1, 2, 3, 4, 5];
    f(&v);
    v.push(6);
    dbg!(v);
}

fn main()
{
    g();
}

Can I massage it a bit so that it works?

MWB
  • 11,740
  • 6
  • 46
  • 91
  • 2
    Yes, you can share an immutable borrow with multiple threads, but you will need to use [`std::thread::scope`](https://doc.rust-lang.org/stable/std/thread/fn.scope.html). [Here](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d0d6c66d937e867013ae803a55afee7b) is what using it would look like in your case. – kmdreko Feb 27 '23 at 20:53
  • Please, consider formatting your code properly. – Miiao Feb 28 '23 at 08:33
  • @Miiao Matching braces are objectively better. This is why Linux uses them. While I appreciate the value of conventions, Rust's conventions are dead wrong here. Sorry, but the Emperor has no clothes. – MWB Mar 01 '23 at 05:35

1 Answers1

2

Can I massage it a bit so that it works?

Yes, the secret lies in thread::scope, which does not require data captured by the closure to be 'static, because it guarantees that all threads are finished when the scope is finished:

use std::thread;

fn f(v: &[i64]) {
    let n = v.len();
    
    thread::scope(|s| {
        for i in 0..n {
            s.spawn(move || {
                println!("thread {}, v[{}] = {}", i, i, v[i]);    
            });
        }
    });
}

fn g() {
    let mut v = vec![1, 2, 3, 4, 5];
    f(&v);
    v.push(6);
    dbg!(v);
}

fn main() {
    g();
}

Playground.

Jonas Fassbender
  • 2,371
  • 1
  • 3
  • 19
  • Thanks! I guess my Rust isn't up-to-date enough to have it (I'm using the one in Debian Stable) – MWB Feb 27 '23 at 20:58
  • In that case try to pass `v` as an `Arc` into `f` and move the value out of the `Arc` after you are finished. Like [this](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=451905bcd44bb7bd57044cb8c42ec384). – Jonas Fassbender Feb 27 '23 at 21:03