Noodles for every philosopher

This commit is contained in:
Aode (Lion) 2022-02-22 13:04:06 -06:00
commit 0984849288
4 changed files with 132 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

7
Cargo.lock generated Normal file
View file

@ -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"

8
Cargo.toml Normal file
View file

@ -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]

116
src/main.rs Normal file
View file

@ -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<Mutex<ForkId>>,
second: Arc<Mutex<ForkId>>,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>> {
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<Self>) {}
fn wake_by_ref(self: &Arc<Self>) {}
}
impl std::future::Future for YieldNow {
type Output = ();
fn poll(
mut self: std::pin::Pin<&mut Self>,
_: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
if let Some(()) = self.as_mut().0.take() {
std::task::Poll::Pending
} else {
std::task::Poll::Ready(())
}
}
}
async fn yield_now() {
YieldNow(Some(())).await
}