Skip to content

Commit

Permalink
adding working solution
Browse files Browse the repository at this point in the history
  • Loading branch information
noahgift committed Jul 23, 2023
1 parent 32d3fe4 commit fdfdfae
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 0 deletions.
11 changes: 11 additions & 0 deletions dining-philosopher/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "dining-philosopher"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rand = "0.8.5"
parking_lot = "0.12.1"

13 changes: 13 additions & 0 deletions dining-philosopher/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
format:
cargo fmt --quiet

lint:
cargo clippy --quiet

test:
cargo test --quiet

run:
cargo run

all: format lint test run
131 changes: 131 additions & 0 deletions dining-philosopher/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* The dining philosophers problem involves multiple threads needing
* synchronized access to shared resources, risking deadlock.
*
* This code models philosophers as threads and forks as shared Mutex<()>
* wrapped in Arc for thread-safe reference counting.
*
* To prevent deadlock from a "deadly embrace" of waiting for neighboring
* forks, philosophers acquire lower numbered forks first. This breaks
* symmetry and avoids circular waiting.
*
* The Mutexes provide exclusive fork access. The Arc allows sharing forks
* between philosophers.
*
* The simulation prints start time, eating duration, and total time for
* all philosophers. Total time approximately equals philosophers divided
* by forks, as that number can eat concurrently.
*
* Key techniques:
* - Used Mutex<()> to represent exclusive fork access
* - Wrapped in Arc to share Mutexes between threads
* - Numbered philosophers and acquire lower fork first
* - Prints timing metrics for simulation
*/

use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};

struct Fork {
id: u32,
mutex: Mutex<()>,
}

struct Philosopher {
id: u32,
name: String,
left_fork: Arc<Fork>,
right_fork: Arc<Fork>,
}

impl Philosopher {
fn new(id: u32, name: &str, left_fork: Arc<Fork>, right_fork: Arc<Fork>) -> Philosopher {
Philosopher {
id,
name: name.to_string(),
left_fork,
right_fork,
}
}

fn eat(&self) {
let (first_fork, second_fork) = if self.id % 2 == 0 {
(&self.left_fork, &self.right_fork)
} else {
(&self.right_fork, &self.left_fork)
};

let _first_guard = first_fork.mutex.lock().unwrap();
println!("{} picked up fork {}.", self.name, first_fork.id);
let _second_guard = second_fork.mutex.lock().unwrap();
println!("{} picked up fork {}.", self.name, second_fork.id);

println!("{} is eating.", self.name);
thread::sleep(Duration::from_secs(1));
println!("{} finished eating.", self.name);

println!("{} put down fork {}.", self.name, first_fork.id);
println!("{} put down fork {}.", self.name, second_fork.id);
}
}

fn main() {
println!("Dining Philosophers Problem: 15 Philosophers, 4 Forks...Yikes!!");

//we only have 4 forks at the table
let forks = (0..4)
.map(|id| {
Arc::new(Fork {
id,
mutex: Mutex::new(()),
})
})
.collect::<Vec<_>>();

let philosophers = vec![
("Jürgen Habermas", 0, 1),
("Friedrich Engels", 1, 2),
("Karl Marx", 2, 3),
("Thomas Piketty", 3, 0),
("Michel Foucault", 0, 1),
("Socrates", 1, 2),
("Plato", 2, 3),
("Aristotle", 3, 0),
("Pythagoras", 0, 1),
("Heraclitus", 1, 2),
("Democritus", 2, 3),
("Diogenes", 3, 0),
("Epicurus", 0, 1),
("Zeno of Citium", 1, 2),
("Thales of Miletus", 2, 3),
]
.into_iter()
.enumerate()
.map(|(id, (name, left, right))| {
Philosopher::new(
id as u32,
name,
Arc::clone(&forks[left]),
Arc::clone(&forks[right]),
)
})
.collect::<Vec<_>>();

let start = Instant::now();

let handles = philosophers
.into_iter()
.map(|philosopher| {
thread::spawn(move || {
philosopher.eat();
})
})
.collect::<Vec<_>>();

for handle in handles {
handle.join().unwrap();
}

println!("Total time: {:?}", start.elapsed());
}

0 comments on commit fdfdfae

Please sign in to comment.