Take the following code:
use std::{sync::{Arc, Mutex}, thread::{self, JoinHandle}};
const SIZE: usize = 15;
const THREADS:usize = 5;
fn double(M: Vec<Vec<i64>>) -> (Vec<Vec<i64>>, Vec<Vec<i64>>) {
let new_mat = vec![vec![0; SIZE]; SIZE];
let arc = Arc::new(Mutex::new(new_mat));
let mat_arc = Arc::new(Mutex::new(M));
let handles: Vec<JoinHandle<()>> = (0..THREADS).map(|i| {
let c = Arc::clone(&arc);
let m = Arc::clone(&mat_arc);
thread::spawn(move || {
let mut k = i;
while k < SIZE {
println!("Thread {} filling row {}", i, k);
let mut mx = c.lock().unwrap();
let mo = m.lock().unwrap();
for j in 0..SIZE {
mx[k][j] = mo[k][j]*2;
}
k += THREADS;
}
})
}).collect();
for h in handles {
h.join().unwrap();
}
(Arc::try_unwrap(mat_arc).unwrap().into_inner().unwrap(), Arc::try_unwrap(arc).unwrap().into_inner().unwrap())
}
fn main() {
let mut count = 0;
let mut M = vec![vec![0; SIZE]; SIZE];
for i in 0..SIZE {
for j in 0..SIZE {
M[i][j] = count as i64;
count += 1;
}
}
let (M, new_mat) = double(M);
println!("Original Matrix:");
println!("{:?}", M);
println!("Double Matrix:");
println!("{:?}", new_mat);
}
You will see that the function double takes ownership of the matrix M, creates a new matrix and populates it (in a multithreaded way) with the doubled values of matrix M and returns both matrices.
I don't particularly like this solution and I would like to pass an immutable reference to M instead. However, if I passed M as an immutable reference, the compiler would complain that the reference might not live long enough and that should have static lifetime to be used safely with threads. That would be ok for contrived and small examples, but it would be a nightmare in case I were to do something slightly more complicated.
Is there a way of doing what I want to do? Essentially my function signature would have to be:
fn double (M: &Vec<Vec<i64>>) -> Vec<Vec<i64>>