Sync
This commit is contained in:
parent
6f050a029e
commit
776bba907c
3887 changed files with 59894 additions and 7280 deletions
|
|
@ -1,4 +1,4 @@
|
|||
The dining philosophers problem illustrates non-composability of low-level synchronization primitives like [[semaphore]]s. It is a modification of a problem posed by Edsger Dijkstra.
|
||||
The dining philosophers problem illustrates non-composability of low-level synchronization primitives like [[semaphore]]s. It is a modification of a problem posed by [https://en.wikipedia.org/wiki/Edsger_W._Dijkstra Edsger Dijkstra.]
|
||||
|
||||
Five philosophers, Aristotle, Kant, Spinoza, Marx, and Russell (the [[task]]s) spend their time thinking and eating spaghetti. They eat at a round table with five individual seats. For eating each philosopher needs two forks (the resources). There are five forks on the table, one left and one right of each seat. When a philosopher cannot grab both forks it sits and waits. Eating takes random time, then the philosopher puts the forks down and leaves the dining room. After spending some random time thinking about the nature of the universe, he again becomes hungry, and the circle repeats itself.
|
||||
|
||||
|
|
|
|||
|
|
@ -81,9 +81,9 @@ private:
|
|||
|
||||
// attempt to grab forks
|
||||
if( can_grab_fork( fork_left ) ) {
|
||||
ForkLock::lock_guard lock_left( *fork_left, boost::adopt_lock );
|
||||
ForkLock lock_left( *fork_left, boost::adopt_lock );
|
||||
if( can_grab_fork( fork_right ) ) {
|
||||
ForkLock::lock_guard lock_right( *fork_right, boost::adopt_lock );
|
||||
ForkLock lock_right( *fork_right, boost::adopt_lock );
|
||||
// eating
|
||||
mp_logger->log( boost::str( boost::format( "%1% is eating (%2%)..." ) % m_name % m_meals_left ) );
|
||||
wait();
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ void main() {
|
|||
fork = new Mutex();
|
||||
|
||||
defaultPoolThreads = forks.length;
|
||||
foreach (uint i, philo; taskPool.parallel(philosophers)) {
|
||||
foreach (i, philo; taskPool.parallel(philosophers)) {
|
||||
foreach (_; 0 .. 100) {
|
||||
eat(i, philo, forks);
|
||||
think(philo);
|
||||
|
|
|
|||
65
Task/Dining-philosophers/Haskell/dining-philosophers-1.hs
Normal file
65
Task/Dining-philosophers/Haskell/dining-philosophers-1.hs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
module Philosophers where
|
||||
|
||||
import Control.Monad
|
||||
import Control.Concurrent
|
||||
import Control.Concurrent.STM
|
||||
import System.Random
|
||||
|
||||
-- TMVars are transactional references. They can only be used in transactional actions.
|
||||
-- They are either empty or contain one value. Taking an empty reference fails and
|
||||
-- putting a value in a full reference fails. A transactional action only succeeds
|
||||
-- when all the component actions succeed, else it rolls back and retries until it
|
||||
-- succeeds.
|
||||
-- The Int is just for display purposes.
|
||||
type Fork = TMVar Int
|
||||
|
||||
newFork :: Int -> IO Fork
|
||||
newFork i = newTMVarIO i
|
||||
|
||||
-- The basic transactional operations on forks
|
||||
takeFork :: Fork -> STM Int
|
||||
takeFork fork = takeTMVar fork
|
||||
|
||||
releaseFork :: Int -> Fork -> STM ()
|
||||
releaseFork i fork = putTMVar fork i
|
||||
|
||||
type Name = String
|
||||
|
||||
runPhilosopher :: Name -> (Fork, Fork) -> IO ()
|
||||
runPhilosopher name (left, right) = forever $ do
|
||||
putStrLn (name ++ " is hungry.")
|
||||
|
||||
-- Run the transactional action atomically.
|
||||
-- The type system ensures this is the only way to run transactional actions.
|
||||
(leftNum, rightNum) <- atomically $ do
|
||||
leftNum <- takeFork left
|
||||
rightNum <- takeFork right
|
||||
return (leftNum, rightNum)
|
||||
|
||||
putStrLn (name ++ " got forks " ++ show leftNum ++ " and " ++ show rightNum ++ " and is now eating.")
|
||||
delay <- randomRIO (1,10)
|
||||
threadDelay (delay * 1000000) -- 1, 10 seconds. threadDelay uses nanoseconds.
|
||||
putStrLn (name ++ " is done eating. Going back to thinking.")
|
||||
|
||||
atomically $ do
|
||||
releaseFork leftNum left
|
||||
releaseFork rightNum right
|
||||
|
||||
delay <- randomRIO (1, 10)
|
||||
threadDelay (delay * 1000000)
|
||||
|
||||
philosophers :: [String]
|
||||
philosophers = ["Aristotle", "Kant", "Spinoza", "Marx", "Russel"]
|
||||
|
||||
main = do
|
||||
forks <- mapM newFork [1..5]
|
||||
let namedPhilosophers = map runPhilosopher philosophers
|
||||
forkPairs = zip forks (tail . cycle $ forks)
|
||||
philosophersWithForks = zipWith ($) namedPhilosophers forkPairs
|
||||
|
||||
putStrLn "Running the philosophers. Press enter to quit."
|
||||
|
||||
mapM_ forkIO philosophersWithForks
|
||||
|
||||
-- All threads exit when the main thread exits.
|
||||
getLine
|
||||
29
Task/Dining-philosophers/Haskell/dining-philosophers-2.hs
Normal file
29
Task/Dining-philosophers/Haskell/dining-philosophers-2.hs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
global forks, names
|
||||
|
||||
procedure main(A)
|
||||
names := ["Aristotle","Kant","Spinoza","Marks","Russell"]
|
||||
write("^C to terminate")
|
||||
nP := *names
|
||||
forks := [: |mutex([])\nP :]
|
||||
every p := !nP do thread philosopher(p)
|
||||
delay(-1)
|
||||
end
|
||||
|
||||
procedure philosopher(n)
|
||||
f1 := forks[min(n, n%*forks+1)]
|
||||
f2 := forks[max(n, n%*forks+1)]
|
||||
repeat {
|
||||
write(names[n]," thinking")
|
||||
delay(1000*?5)
|
||||
write(names[n]," hungry")
|
||||
repeat {
|
||||
fork1 := lock(f1)
|
||||
if fork2 := trylock(f2) then {
|
||||
write(names[n]," eating")
|
||||
delay(1000*?5)
|
||||
break (unlock(fork2), unlock(fork1)) # full
|
||||
}
|
||||
unlock(fork1) # Free first fork and go back to waiting
|
||||
}
|
||||
}
|
||||
end
|
||||
50
Task/Dining-philosophers/Perl/dining-philosophers.pl
Normal file
50
Task/Dining-philosophers/Perl/dining-philosophers.pl
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
use threads;
|
||||
use threads::shared;
|
||||
my @names = qw(Aristotle Kant Spinoza Marx Russell);
|
||||
|
||||
my @forks = ('On Table') x @names;
|
||||
share $forks[$_] for 0 .. $#forks;
|
||||
|
||||
sub pick_up_forks {
|
||||
my $philosopher = shift;
|
||||
my ($first, $second) = ($philosopher, $philosopher-1);
|
||||
($first, $second) = ($second, $first) if $philosopher % 2;
|
||||
for my $fork ( @forks[ $first, $second ] ) {
|
||||
lock $fork;
|
||||
cond_wait($fork) while $fork ne 'On Table';
|
||||
$fork = 'In Hand';
|
||||
}
|
||||
}
|
||||
|
||||
sub drop_forks {
|
||||
my $philosopher = shift;
|
||||
for my $fork ( @forks[$philosopher, $philosopher-1] ) {
|
||||
lock $fork;
|
||||
die unless $fork eq 'In Hand';
|
||||
$fork = 'On Table';
|
||||
cond_signal($fork);
|
||||
}
|
||||
}
|
||||
|
||||
sub philosopher {
|
||||
my $philosopher = shift;
|
||||
my $name = $names[$philosopher];
|
||||
for my $meal ( 1..5 ) {
|
||||
print $name, " is pondering\n";
|
||||
sleep 1 + rand 8;
|
||||
print $name, " is hungry\n";
|
||||
pick_up_forks( $philosopher );
|
||||
print $name, " is eating\n";
|
||||
sleep 1 + rand 8;
|
||||
drop_forks( $philosopher );
|
||||
}
|
||||
print $name, " is done\n";
|
||||
}
|
||||
|
||||
my @t = map { threads->new(\&philosopher, $_) } 0 .. $#names;
|
||||
for my $thread ( @t ) {
|
||||
$thread->join;
|
||||
}
|
||||
|
||||
print "Done\n";
|
||||
__END__
|
||||
99
Task/Dining-philosophers/Rust/dining-philosophers.rust
Normal file
99
Task/Dining-philosophers/Rust/dining-philosophers.rust
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
extern mod extra;
|
||||
use std::rt::io::timer;
|
||||
use extra::comm::DuplexStream;
|
||||
|
||||
fn phil(phil: ~str, diner: &DuplexStream<int, int>, firstChopstick: int, secondChopstick: int)
|
||||
{
|
||||
let mut sleep_time: u64;
|
||||
print(fmt!("%s sat down\n", phil));
|
||||
for _ in range(1,3)
|
||||
{
|
||||
print(fmt!("%s is thinking\n", phil));
|
||||
sleep_time = std::rand::random();
|
||||
timer::sleep((sleep_time%5)*500);
|
||||
print(fmt!("%s is hungry\n", phil));
|
||||
//get left chopstick
|
||||
diner.send(firstChopstick);
|
||||
let mut recv: int = diner.recv();
|
||||
while recv == 0
|
||||
{
|
||||
diner.send(firstChopstick);
|
||||
recv = diner.recv();
|
||||
}
|
||||
print(fmt!("%s picked up his left chopstick\n", phil));
|
||||
//get right chopstick
|
||||
diner.send(secondChopstick);
|
||||
recv = diner.recv();
|
||||
while recv == 0
|
||||
{
|
||||
diner.send(secondChopstick);
|
||||
recv = diner.recv();
|
||||
}
|
||||
print(fmt!("%s picked up his right chopstick\n", phil));
|
||||
//eat
|
||||
print(fmt!("%s is eating...\n", phil));
|
||||
sleep_time = std::rand::random();
|
||||
timer::sleep((sleep_time%3)*500);
|
||||
print(fmt!("%s is done eating\n", phil));
|
||||
//set down left chopstick
|
||||
print(fmt!("%s set down his left chopstick\n", phil));
|
||||
diner.send(-1*firstChopstick);
|
||||
//set down right chopstick
|
||||
print(fmt!("%s set down his right chopstick\n", phil));
|
||||
diner.send(-1*secondChopstick);
|
||||
|
||||
}
|
||||
diner.send(0);
|
||||
diner.recv();
|
||||
print(fmt!("%s has exited\n", phil));
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
//set the table:
|
||||
//false means chopstick is on the table
|
||||
//true means chopstick is taken
|
||||
let mut chopsticks: ~[bool] = ~[false, false, false, false, false];
|
||||
|
||||
//diner_ will try to take resources from the table, host_
|
||||
//will respond with whether that action was successful.
|
||||
let (diner1, host1) = DuplexStream();
|
||||
let (diner2, host2) = DuplexStream();
|
||||
let (diner3, host3) = DuplexStream();
|
||||
let (diner4, host4) = DuplexStream();
|
||||
let (diner5, host5) = DuplexStream();
|
||||
|
||||
//Make the first 4 "right-handed" philosophers
|
||||
do spawn{ phil(~"Hobbes", &diner1, 1, 2); }
|
||||
do spawn{ phil(~"Locke", &diner2, 2, 3); }
|
||||
do spawn{ phil(~"Machiavelli", &diner3, 3, 4); }
|
||||
do spawn{ phil(~"Montesquieu", &diner4, 4, 5); }
|
||||
//Make the last, "left-handed" philosopher
|
||||
do spawn{ phil(~"Rousseau", &diner5, 1, 5); }
|
||||
|
||||
//keep track of number of people still at the table
|
||||
let mut remaining = 5;
|
||||
while remaining > 0
|
||||
{
|
||||
matchReq(&mut chopsticks, &host1, &mut remaining);
|
||||
matchReq(&mut chopsticks, &host2, &mut remaining);
|
||||
matchReq(&mut chopsticks, &host3, &mut remaining);
|
||||
matchReq(&mut chopsticks, &host4, &mut remaining);
|
||||
matchReq(&mut chopsticks, &host5, &mut remaining);
|
||||
std::task::deschedule();
|
||||
}
|
||||
}
|
||||
|
||||
fn matchReq(chopsticks: &mut ~[bool], host: &DuplexStream<int, int>, remaining: &mut int) {
|
||||
if (host.peek())
|
||||
{
|
||||
let from = host.try_recv();
|
||||
match from
|
||||
{
|
||||
Some(0) => { *remaining += -1; host.try_send(0); return; },
|
||||
Some(x) if x > 0 => { if(chopsticks[x-1]) { host.send(0); } else { chopsticks[x-1] = true; host.send(1); } },
|
||||
Some(x) => { chopsticks[(-x)-1] = false; },
|
||||
None => { *remaining += -1; host.try_send(0); return; }
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue