Skip to content

Instantly share code, notes, and snippets.

@jeremyjh
Last active August 29, 2015 14:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeremyjh/a28423d8dae3a07536c0 to your computer and use it in GitHub Desktop.
Save jeremyjh/a28423d8dae3a07536c0 to your computer and use it in GitHub Desktop.
Rust Dining Philosphers implementation using fair Arbitrator solution
extern crate rand;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{Sender, Receiver, channel};
use rand::Rng;
fn main() {
let waiter = Waiter::new();
let philosophers = vec![
Philosopher::new("Baruch Spinoza", 0, 1),
Philosopher::new("Gilles Deleuze", 1, 2),
Philosopher::new("Karl Marx", 2, 3),
Philosopher::new("Friedrich Nietzsche", 3, 4),
Philosopher::new("Michel Foucault", 4, 0),
];
let handles: Vec<_> = philosophers.into_iter().map(|p| {
let waiter = waiter.clone();
let phil = Arc::new(p);
thread::spawn(move || {
let mut rng = rand::thread_rng();
for _ in 0..5 {
let n = (rng.gen::<u32>() % 5) * 1000;
think(&phil,n);
let n = (rng.gen::<u32>() % 5) * 1000;
eat(&phil,&waiter,n);
}
})
}).collect();
for h in handles {
h.join().ok().expect("Philosopher down!");
}
println!("All done!");
}
fn eat(phil: &Arc<Philosopher>, waiter: &Waiter, duration: u32) {
waiter.get_forks(phil);
println!("{} is eating.", phil.name);
thread::sleep_ms(duration);
println!("{} is done eating.", phil.name);
waiter.put_forks(phil);
}
fn think(phil: &Arc<Philosopher>, duration: u32) {
println!("{} is thinking.", phil.name);
thread::sleep_ms(duration);
println!("{} is done thinking.", phil.name);
}
struct Philosopher {
name: String,
left: usize,
right: usize,
}
impl Philosopher {
fn new(name: &str, left: usize, right: usize) -> Philosopher {
Philosopher {
name: name.to_string(),
left: left,
right: right,
}
}
}
enum ForkRequest {
Take,
Return
}
struct Request {
phil: Arc<Philosopher>,
resp: Sender<()>,
request: ForkRequest
}
#[derive (Clone)]
struct Waiter {
sender: Sender<Request>
}
impl Waiter {
fn new () -> Waiter {
let (tx, rx) = channel();
Waiter::start_serving(rx);
Waiter{sender: tx}
}
fn start_serving(rx: Receiver<Request>) {
thread::spawn(move || {
let mut forks = [ true, true, true, true, true ];
let mut pended = Vec::new();
while let Ok(rq) = rx.recv() { //exit on Err(_)
match rq.request {
ForkRequest::Take =>
if forks[rq.phil.left] && forks[rq.phil.right] {
forks[rq.phil.left] = false;
forks[rq.phil.right] = false;
rq.resp.send(()).ok().expect("Failed to send response!");
} else {
println!("{} is waiting.", rq.phil.name);
pended.push(rq);
},
ForkRequest::Return => {
forks[rq.phil.left] = true;
forks[rq.phil.right] = true;
rq.resp.send(()).ok().expect("Failed to send response!");
}
}
pended.retain( |rq| {
if forks[rq.phil.left] && forks[rq.phil.right]{
forks[rq.phil.left] = false;
forks[rq.phil.right] = false;
rq.resp.send(()).ok().expect("Failed to send response!");
false
} else {
true
}
});
};}
);
}
fn get_forks (&self, phil: &Arc<Philosopher>) -> (){
let (tx, rx) = channel();
let rq = Request{phil: phil.clone(), resp: tx, request: ForkRequest::Take};
self.sender.send(rq).ok().expect("Send get_forks failed!");
rx.recv().ok().expect("No response to get_forks!");
}
fn put_forks (&self, phil: &Arc<Philosopher>) -> () {
let (tx, rx) = channel();
let rq = Request{phil: phil.clone(), resp: tx, request: ForkRequest::Return};
self.sender.send(rq).ok().expect("Send put_forks failed!");
rx.recv().ok().expect("No response to put_forks!");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment