From 0984849288c2ba52347c16be8263a1c2d7ab8936 Mon Sep 17 00:00:00 2001 From: "Aode (Lion)" Date: Tue, 22 Feb 2022 13:04:06 -0600 Subject: [PATCH] Noodles for every philosopher --- .gitignore | 1 + Cargo.lock | 7 ++++ Cargo.toml | 8 ++++ src/main.rs | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..04da715 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "philosophy" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..af2692a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "philosophy" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..55cff5a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,116 @@ +use std::sync::{Arc, Mutex}; + +async fn eat(philosopher: usize, ForkId(first): ForkId, ForkId(second): ForkId) { + for _ in 0..3 { + println!( + "Philosopher {}: I'm eating with forks {} and {}", + philosopher, first, second + ); + yield_now().await; + } +} + +fn philosopher( + id: usize, + first: Arc>, + second: Arc>, +) -> std::pin::Pin>> { + Box::pin(async move { + loop { + if let Ok(first_guard) = first.try_lock() { + println!("Philosopher {}: got first guard", id); + yield_now().await; + if let Ok(second_guard) = second.try_lock() { + eat(id, *first_guard, *second_guard).await; + + drop(second_guard); + drop(first_guard); + break; + } + println!("Philosopher {}: did not get second guard", id); + yield_now().await; + drop(first_guard); + continue; + } + println!("Philosopher {}: did not get first guard", id); + yield_now().await; + } + }) +} + +fn philosophy(num_philosophers: usize) { + let mut mutexes = Vec::new(); + for i in 0..num_philosophers { + mutexes.push(Arc::new(Mutex::new(ForkId(i)))); + } + + let mut futures = Vec::new(); + for i in 0..num_philosophers { + let next_index = (i + 1) % num_philosophers; + + let [first_index, second_index] = if (i % 2) == 0 { + [i, next_index] + } else { + [next_index, i] + }; + + let first = Arc::clone(&mutexes[first_index]); + let second = Arc::clone(&mutexes[second_index]); + + futures.push(philosopher(i, first, second)); + } + + let waker = Arc::new(DummyWaker).into(); + let mut context = std::task::Context::from_waker(&waker); + + for iteration in 0.. { + println!("state at {}:", iteration); + futures = futures.drain(..).filter_map(|mut future| { + if future.as_mut().poll(&mut context).is_ready() { + None + } else { + Some(future) + } + }).collect(); + + if futures.is_empty() { + break; + } + } + + println!("Hello, world!"); +} + +fn main() { + philosophy(4096); +} + +#[derive(Clone, Copy)] +struct ForkId(usize); + +struct YieldNow(Option<()>); + +struct DummyWaker; +impl std::task::Wake for DummyWaker { + fn wake(self: Arc) {} + fn wake_by_ref(self: &Arc) {} +} + +impl std::future::Future for YieldNow { + type Output = (); + + fn poll( + mut self: std::pin::Pin<&mut Self>, + _: &mut std::task::Context<'_>, + ) -> std::task::Poll { + if let Some(()) = self.as_mut().0.take() { + std::task::Poll::Pending + } else { + std::task::Poll::Ready(()) + } + } +} + +async fn yield_now() { + YieldNow(Some(())).await +}