// Copyright 2024 Google LLC
// SPDX-License-Identifier: Apache-2.0
use std::sync::{Arc, Mutex, mpsc};
use std::thread;
use std::time::Duration;
struct Chopstick;
struct Philosopher {
name: String,
left_chopstick: Arc<Mutex<Chopstick>>,
right_chopstick: Arc<Mutex<Chopstick>>,
thoughts: mpsc::SyncSender<String>,
}
impl Philosopher {
fn think(&self) {
self.thoughts
.send(format!("Eureka! {} has a new idea!", &self.name))
.unwrap();
}
fn eat(&self) {
println!("{} is trying to eat", &self.name);
let _left = self.left_chopstick.lock().unwrap();
let _right = self.right_chopstick.lock().unwrap();
println!("{} is eating...", &self.name);
thread::sleep(Duration::from_millis(10));
}
}
static PHILOSOPHERS: &[&str] =
&["Socrates", "Hypatia", "Plato", "Aristotle", "Pythagoras"];
fn main() {
let (tx, rx) = mpsc::sync_channel(10);
let chopsticks = PHILOSOPHERS
.iter()
.map(|_| Arc::new(Mutex::new(Chopstick)))
.collect::<Vec<_>>();
for i in 0..chopsticks.len() {
let tx = tx.clone();
let mut left_chopstick = Arc::clone(&chopsticks[i]);
let mut right_chopstick =
Arc::clone(&chopsticks[(i + 1) % chopsticks.len()]);
// To avoid a deadlock, we have to break the symmetry
// somewhere. This will swap the chopsticks without deinitializing
// either of them.
if i == chopsticks.len() - 1 {
std::mem::swap(&mut left_chopstick, &mut right_chopstick);
}
let philosopher = Philosopher {
name: PHILOSOPHERS[i].to_string(),
thoughts: tx,
left_chopstick,
right_chopstick,
};
thread::spawn(move || {
for _ in 0..100 {
philosopher.eat();
philosopher.think();
}
});
}
drop(tx);
for thought in rx {
println!("{thought}");
}
}