Noodles for every philosopher
This commit is contained in:
commit
0984849288
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal 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
8
Cargo.toml
Normal 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
116
src/main.rs
Normal 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
|
||||
}
|
Loading…
Reference in a new issue