// Copyright 2023 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ANCHOR: solution // ANCHOR: Philosopher use std::sync::Arc; use tokio::sync::mpsc::{self, Sender}; use tokio::sync::Mutex; use tokio::time; struct Fork; struct Philosopher { name: String, // ANCHOR_END: Philosopher left_fork: Arc>, right_fork: Arc>, thoughts: Sender, } // ANCHOR: Philosopher-think impl Philosopher { async fn think(&self) { self.thoughts .send(format!("Eureka! {} has a new idea!", &self.name)) .await .unwrap(); } // ANCHOR_END: Philosopher-think // ANCHOR: Philosopher-eat async fn eat(&self) { // Pick up forks... // ANCHOR_END: Philosopher-eat let _first_lock = self.left_fork.lock().await; // Add a delay before picking the second fork to allow the execution // to transfer to another task time::sleep(time::Duration::from_millis(1)).await; let _second_lock = self.right_fork.lock().await; // ANCHOR: Philosopher-eat-body println!("{} is eating...", &self.name); time::sleep(time::Duration::from_millis(5)).await; // ANCHOR_END: Philosopher-eat-body // The locks are dropped here // ANCHOR: Philosopher-eat-end } } static PHILOSOPHERS: &[&str] = &["Socrates", "Hypatia", "Plato", "Aristotle", "Pythagoras"]; #[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 philosophers let (philosophers, mut rx) = { let mut philosophers = vec![]; let (tx, rx) = mpsc::channel(10); for (i, name) in PHILOSOPHERS.iter().enumerate() { let left_fork = Arc::clone(&forks[i]); let right_fork = Arc::clone(&forks[(i + 1) % PHILOSOPHERS.len()]); // To avoid a deadlock, we have to break the symmetry // somewhere. This will swap the forks without deinitializing // either of them. if i == 0 { std::mem::swap(&mut left_fork, &mut right_fork); } philosophers.push(Philosopher { name: name.to_string(), left_fork, right_fork, thoughts: tx.clone(), }); } (philosophers, rx) // tx is dropped here, so we don't need to explicitly drop it later }; // Make them think and eat for phil in philosophers { tokio::spawn(async move { for _ in 0..100 { phil.think().await; phil.eat().await; } }); } // Output their thoughts while let Some(thought) = rx.recv().await { println!("Here is a thought: {thought}"); } }