Last active
August 29, 2015 14:21
-
-
Save eborden/389db957c0449a77b6c1 to your computer and use it in GitHub Desktop.
Rust's "Dining Philosophers" solution reimplemented in unidiomatic Haskell
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main where | |
import Prelude hiding (sequence) | |
import Control.Concurrent | |
import Data.Foldable | |
import Data.Traversable | |
data Philosopher = Philosopher | |
{ name :: String | |
, left :: Int | |
, right :: Int | |
} | |
data Table = Table { forks :: [MVar ()] } | |
type BufferLock = MVar () | |
eat :: BufferLock -> Table -> Philosopher -> IO () | |
eat buf t p = do | |
let l = forks t !! left p | |
r = forks t !! right p | |
withMVar l (\_ -> withMVar r (\ _ -> do | |
putStrLock buf (name p ++ " is eating") | |
threadDelay 1000000 | |
putStrLock buf (name p ++ " is done eating"))) | |
table :: Int -> IO Table | |
table i = fmap Table . sequence . take i . repeat $ newMVar () | |
philosophers :: [Philosopher] | |
philosophers = | |
[ Philosopher "1" 0 1 | |
, Philosopher "2" 1 2 | |
, Philosopher "3" 2 3 | |
, Philosopher "4" 3 4 | |
, Philosopher "5" 0 4 | |
] | |
-- Avoids interleaving of string output | |
putStrLock :: BufferLock -> String -> IO () | |
putStrLock m s = withMVar m (\_ -> putStrLn s) | |
main = do | |
buf <- newMVar () | |
t <- table (length philosophers) | |
forM_ philosophers (forkIO . eat buf t) | |
getLine |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::thread; | |
use std::sync::{Mutex, Arc}; | |
struct Philosopher { | |
name: String, | |
left: usize, | |
right: usize, | |
} | |
impl Philosopher { | |
fn new(name: &str, left: usize, right: usize) -> Self { | |
Philosopher { | |
name: name.to_string(), | |
left: left, | |
right: right, | |
} | |
} | |
fn eat(&self, table: &Table) { | |
let _left = table.forks[self.left].lock().unwrap(); | |
let _right = table.forks[self.right].lock().unwrap(); | |
println!("{} is eating", self.name); | |
thread::sleep_ms(1000); | |
println!("{} is done eating", self.name); | |
} | |
} | |
struct Table { | |
forks: Vec<Mutex<()>>, | |
} | |
fn main() { | |
let t = Arc::new(Table {forks: | |
vec![ Mutex::new(()) | |
, Mutex::new(()) | |
, Mutex::new(()) | |
, Mutex::new(()) | |
, Mutex::new(()) | |
] | |
}); | |
let p = vec![ Philosopher::new("1", 0, 1) | |
, Philosopher::new("2", 1 , 2) | |
, Philosopher::new("3", 2, 3) | |
, Philosopher::new("4", 3, 4) | |
, Philosopher::new("5", 0, 4) | |
]; | |
let handles: Vec<_> = p.into_iter().map(|x| { | |
let t = t.clone(); | |
thread::spawn(move || { | |
x.eat(&t); | |
}) | |
}).collect(); | |
for h in handles { | |
h.join().unwrap(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment