I am trying to implement a kind of concurrent Iterator where an array is immutable borrowed between threads but I cannot get around the borrow checker: (Playground)
use std::sync::mpsc::channel;
use threadpool::ThreadPool;
use std::sync::mpsc::Receiver;
const N: i32 = 10;
#[derive(Debug)]
struct ConcurrentIterator {
array: Vec<i32>,
threadpool: ThreadPool,
receiver: Receiver<i32>,
}
impl ConcurrentIterator {
fn new() -> Self {
let (tx, receiver) = channel();
let threadpool = ThreadPool::new(3);
let array = (0..N).map(|el| el*el).collect::<Vec<i32>>();
let s = Self {
array,
threadpool,
receiver,
};
for i in 0..N {
let tx = tx.clone();
let r = &s.array; // array lives as long as Self so this should be possible?
s.threadpool.execute(move ||{
let el = &r[i as usize];
tx.send(*el);
});
};
s
}
}
impl Iterator for ConcurrentIterator {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
match self.receiver.recv() {
Ok(i) => Some(i),
Err(_) => None,
}
}
}
fn main() {
let concurrent_iterator = ConcurrentIterator::new();
for i in concurrent_iterator {
dbg!(i); // should print 1..=10^2 unordered
}
}
Error is s.array does not live long enough and cannot move out of s because it is borrowed
There is no guarantee that the thread will finish its job before anything else happens outside the thread's responsibility (including the destruction of values borrowed by the thread). Thus, threading typically requires that values sent into the thread be 'static. This has nothing to do with r outliving s.
It's simplified code, in the original I need to index into several elements of the precomputed array (and the indices are difficult to calculate before)