I implemented a simple game of life and I want to try multithreading for the first time.
I use a 1D representation of the gamefield according to the formula index = y * height + x
. Each cell is stored in a HashSet
. A cell is alive if its contained in the set.
The relevant part of the code regarding the multithreading ([playground][1]):
extern crate crossbeam_utils; // 0.8.1
use std::collections::HashSet;
use std::sync::Arc;
use crossbeam_utils::thread;
pub struct GameOfLife {
width: u32,
height: u32,
live_cells: HashSet<u32>,
}
impl GameOfLife {
pub fn new(width: u32, height: u32) -> Self {
GameOfLife {
width,
height,
live_cells: HashSet::with_capacity((width * height / 2) as usize),
}
}
fn live_neighbours(&self, pos: u32) -> usize {
let indicies: [i64; 8] = [
pos as i64 - self.width as i64 - 1,
pos as i64 - self.width as i64,
pos as i64 - self.width as i64 + 1,
pos as i64 - 1,
pos as i64 + 1,
pos as i64 + self.width as i64 - 1,
pos as i64 + self.width as i64,
pos as i64 + self.width as i64 + 1,
];
indicies
.iter()
.filter(|&&i| {
i >= 0
&& i < (self.width * self.height) as i64
&& self.live_cells.contains(&(i as u32))
})
.count()
}
fn next_gen(&self, start: u32, stop: u32) -> HashSet<u32> {
(start..stop)
.into_iter()
.filter(
|&i| match (self.live_neighbours(i), self.live_cells.contains(&i)) {
(2, true) | (3, _) => true,
_ => false,
},
)
.collect::<HashSet<u32>>()
}
pub fn next_generation(&mut self) {
let size = self.width * self.height;
let half = (size / 2) as u32;
let mut new_cells = HashSet::<u32>::with_capacity(half as usize);
{
let h1 = thread::scope(|s| s.spawn(|_| self.next_gen(0, half))).unwrap();
let h2 = thread::scope(|s| s.spawn(|_| self.next_gen(half, size))).unwrap();
new_cells.extend(&h1.join().unwrap());
new_cells.extend(&h2.join().unwrap());
}
self.live_cells = new_cells;
}
}
fn main() {
let mut gol = GameOfLife::new(170, 40);
//seed random values ...
for _i in 0..1000000 {
gol.next_generation();
}
}
I am using the crate crossbeam_util="0.8"
.
I am now getting this error:
error: lifetime may not live long enough
--> src/main.rs:60:40
|
60 | let h1 = thread::scope(|s| s.spawn(|_| self.next_gen(0, half))).unwrap();
| -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
| ||
| |return type of closure is ScopedJoinHandle<'2, HashSet<u32>>
| has type `&'1 Scope<'_>`
Updated playground link: playground