You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-06-17 22:57:35 +02:00
104 lines
3.2 KiB
Rust
104 lines
3.2 KiB
Rust
![]() |
// 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: Philosopher
|
||
|
use std::sync::Arc;
|
||
|
use tokio::time;
|
||
|
use tokio::sync::mpsc::{self, Sender};
|
||
|
use tokio::sync::Mutex;
|
||
|
|
||
|
struct Fork;
|
||
|
|
||
|
struct Philosopher {
|
||
|
name: String,
|
||
|
// ANCHOR_END: Philosopher
|
||
|
left_fork: Arc<Mutex<Fork>>,
|
||
|
right_fork: Arc<Mutex<Fork>>,
|
||
|
thoughts: Sender<String>,
|
||
|
}
|
||
|
|
||
|
// 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", "Plato", "Aristotle", "Thales", "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 = forks[i].clone();
|
||
|
let right_fork = forks[(i + 1) % PHILOSOPHERS.len()].clone();
|
||
|
philosophers.push(Philosopher {
|
||
|
name: name.to_string(),
|
||
|
left_fork: if i % 2 == 0 { left_fork.clone() } else { right_fork.clone() },
|
||
|
right_fork: if i % 2 == 0 { right_fork } else { left_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}");
|
||
|
}
|
||
|
}
|