summaryrefslogtreecommitdiff
path: root/examples/dining_philosophers.rs
blob: dc4dd518a56ef1034b2afa79e5dc42dc8452020e (plain)
use std::{thread, time::Duration};

use happylock::{collection, Mutex, ThreadKey};

static PHILOSOPHERS: [Philosopher; 5] = [
	Philosopher {
		name: "Socrates",
		left: 0,
		right: 1,
	},
	Philosopher {
		name: "John Rawls",
		left: 1,
		right: 2,
	},
	Philosopher {
		name: "Jeremy Bentham",
		left: 2,
		right: 3,
	},
	Philosopher {
		name: "John Stuart Mill",
		left: 3,
		right: 4,
	},
	Philosopher {
		name: "Judith Butler",
		left: 4,
		right: 0,
	},
];

static FORKS: [Mutex<()>; 5] = [
	Mutex::new(()),
	Mutex::new(()),
	Mutex::new(()),
	Mutex::new(()),
	Mutex::new(()),
];

struct Philosopher {
	name: &'static str,
	left: usize,
	right: usize,
}

impl Philosopher {
	fn cycle(&self) {
		let key = ThreadKey::get().unwrap();
		thread::sleep(Duration::from_secs(1));

		// safety: no philosopher asks for the same fork twice
		let forks = [&FORKS[self.left], &FORKS[self.right]];
		let forks = unsafe { collection::RefLockCollection::new_unchecked(&forks) };
		let forks = forks.lock(key);
		println!("{} is eating...", self.name);
		thread::sleep(Duration::from_secs(1));
		println!("{} is done eating", self.name);
		drop(forks);
	}
}

fn main() {
	let handles: Vec<_> = PHILOSOPHERS
		.iter()
		.map(|philosopher| thread::spawn(move || philosopher.cycle()))
		// The `collect` is absolutely necessary, because we're using lazy
		// iterators. If `collect` isn't used, then the thread won't spawn
		// until we try to join on it.
		.collect();

	for handle in handles {
		_ = handle.join();
	}
}