diff --git a/src/concurrency/async-exercises/dining-philosophers.md b/src/concurrency/async-exercises/dining-philosophers.md index e84d53b3afc8..6151116e0808 100644 --- a/src/concurrency/async-exercises/dining-philosophers.md +++ b/src/concurrency/async-exercises/dining-philosophers.md @@ -16,8 +16,8 @@ code below to a file called `src/main.rs`, fill out the blanks, and test that ```rust,compile_fail {{#include dining-philosophers.rs:Philosopher}} - // left_fork: ... - // right_fork: ... + // left_chopstick: ... + // right_chopstick: ... // thoughts: ... } @@ -26,7 +26,7 @@ code below to a file called `src/main.rs`, fill out the blanks, and test that {{#include dining-philosophers.rs:Philosopher-eat}} {{#include dining-philosophers.rs:Philosopher-eat-body}} {{#include dining-philosophers.rs:Philosopher-eat-end}} - // Create forks + // Create chopsticks // Create philosophers diff --git a/src/concurrency/async-exercises/dining-philosophers.rs b/src/concurrency/async-exercises/dining-philosophers.rs index e64a2a99e59d..ead7847f9464 100644 --- a/src/concurrency/async-exercises/dining-philosophers.rs +++ b/src/concurrency/async-exercises/dining-philosophers.rs @@ -18,13 +18,13 @@ use std::sync::Arc; use tokio::sync::{mpsc, Mutex}; use tokio::time; -struct Fork; +struct Chopstick; struct Philosopher { name: String, // ANCHOR_END: Philosopher - left_fork: Arc>, - right_fork: Arc>, + left_chopstick: Arc>, + right_chopstick: Arc>, thoughts: mpsc::Sender, } @@ -40,11 +40,11 @@ impl Philosopher { // ANCHOR: Philosopher-eat async fn eat(&self) { - // Keep trying until we have both forks + // Keep trying until we have both chopsticks // ANCHOR_END: Philosopher-eat - // Pick up forks... - let _left_fork = self.left_fork.lock().await; - let _right_fork = self.right_fork.lock().await; + // Pick up chopsticks... + let _left_chopstick = self.left_chopstick.lock().await; + let _right_chopstick = self.right_chopstick.lock().await; // ANCHOR: Philosopher-eat-body println!("{} is eating...", &self.name); @@ -56,30 +56,32 @@ impl Philosopher { } } -static PHILOSOPHERS: &[&str] = - &["Socrates", "Hypatia", "Plato", "Aristotle", "Pythagoras"]; +// tokio scheduler doesn't deadlock with 5 philosophers, so have 2. +static PHILOSOPHERS: &[&str] = &["Socrates", "Hypatia"]; #[tokio::main] async fn main() { // ANCHOR_END: Philosopher-eat-end - // Create forks - let mut forks = vec![]; - (0..PHILOSOPHERS.len()).for_each(|_| forks.push(Arc::new(Mutex::new(Fork)))); + // Create chopsticks + let mut chopsticks = vec![]; + PHILOSOPHERS + .iter() + .for_each(|_| chopsticks.push(Arc::new(Mutex::new(Chopstick)))); // Create philosophers let (philosophers, mut rx) = { let mut philosophers = vec![]; let (tx, rx) = mpsc::channel(10); for (i, name) in PHILOSOPHERS.iter().enumerate() { - let mut left_fork = Arc::clone(&forks[i]); - let mut right_fork = Arc::clone(&forks[(i + 1) % PHILOSOPHERS.len()]); + let mut left_chopstick = Arc::clone(&chopsticks[i]); + let mut right_chopstick = Arc::clone(&chopsticks[(i + 1) % PHILOSOPHERS.len()]); if i == PHILOSOPHERS.len() - 1 { - std::mem::swap(&mut left_fork, &mut right_fork); + std::mem::swap(&mut left_chopstick, &mut right_chopstick); } philosophers.push(Philosopher { name: name.to_string(), - left_fork, - right_fork, + left_chopstick, + right_chopstick, thoughts: tx.clone(), }); } diff --git a/src/concurrency/sync-exercises/dining-philosophers.md b/src/concurrency/sync-exercises/dining-philosophers.md index f36617999b8b..aa0e061aee25 100644 --- a/src/concurrency/sync-exercises/dining-philosophers.md +++ b/src/concurrency/sync-exercises/dining-philosophers.md @@ -7,12 +7,13 @@ minutes: 20 The dining philosophers problem is a classic problem in concurrency: > Five philosophers dine together at the same table. Each philosopher has their -> own place at the table. There is a fork between each plate. The dish served is -> a kind of spaghetti which has to be eaten with two forks. Each philosopher can -> only alternately think and eat. Moreover, a philosopher can only eat their -> spaghetti when they have both a left and right fork. Thus two forks will only -> be available when their two nearest neighbors are thinking, not eating. After -> an individual philosopher finishes eating, they will put down both forks. +> own place at the table. There is a chopstick between each plate. The dish +> served is spaghetti which requires two chopsticks to eat. Each philosopher +> can only alternately think and eat. Moreover, a philosopher can only eat +> their spaghetti when they have both a left and right chopstick. Thus two +> chopsticks will only be available when their two nearest neighbors are +> thinking, not eating. After an individual philosopher finishes eating, they +> will put down both chopsticks. You will need a local [Cargo installation](../../cargo/running-locally.md) for this exercise. Copy the code below to a file called `src/main.rs`, fill out the @@ -22,17 +23,17 @@ blanks, and test that `cargo run` does not deadlock: ```rust,compile_fail {{#include dining-philosophers.rs:Philosopher}} - // left_fork: ... - // right_fork: ... + // left_chopstick: ... + // right_chopstick: ... // thoughts: ... } {{#include dining-philosophers.rs:Philosopher-think}} {{#include dining-philosophers.rs:Philosopher-eat}} - // Pick up forks... + // Pick up chopsticks... {{#include dining-philosophers.rs:Philosopher-eat-end}} - // Create forks + // Create chopsticks // Create philosophers diff --git a/src/concurrency/sync-exercises/dining-philosophers.rs b/src/concurrency/sync-exercises/dining-philosophers.rs index d3bc47edbcff..6900acdb60f1 100644 --- a/src/concurrency/sync-exercises/dining-philosophers.rs +++ b/src/concurrency/sync-exercises/dining-philosophers.rs @@ -18,13 +18,13 @@ use std::sync::{mpsc, Arc, Mutex}; use std::thread; use std::time::Duration; -struct Fork; +struct Chopstick; struct Philosopher { name: String, // ANCHOR_END: Philosopher - left_fork: Arc>, - right_fork: Arc>, + left_chopstick: Arc>, + right_chopstick: Arc>, thoughts: mpsc::SyncSender, } @@ -41,8 +41,8 @@ impl Philosopher { fn eat(&self) { // ANCHOR_END: Philosopher-eat println!("{} is trying to eat", &self.name); - let _left = self.left_fork.lock().unwrap(); - let _right = self.right_fork.lock().unwrap(); + let _left = self.left_chopstick.lock().unwrap(); + let _right = self.right_chopstick.lock().unwrap(); // ANCHOR: Philosopher-eat-end println!("{} is eating...", &self.name); @@ -57,27 +57,29 @@ fn main() { // ANCHOR_END: Philosopher-eat-end let (tx, rx) = mpsc::sync_channel(10); - let forks = (0..PHILOSOPHERS.len()) - .map(|_| Arc::new(Mutex::new(Fork))) + let chopsticks = PHILOSOPHERS + .iter() + .map(|_| Arc::new(Mutex::new(Chopstick))) .collect::>(); - for i in 0..forks.len() { + for i in 0..chopsticks.len() { let tx = tx.clone(); - let mut left_fork = Arc::clone(&forks[i]); - let mut right_fork = Arc::clone(&forks[(i + 1) % forks.len()]); + 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 forks without deinitializing + // somewhere. This will swap the chopsticks without deinitializing // either of them. - if i == forks.len() - 1 { - std::mem::swap(&mut left_fork, &mut right_fork); + 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_fork, - right_fork, + left_chopstick, + right_chopstick, }; thread::spawn(move || {