Time for an 2014 update…

This commit is contained in:
Ingy döt Net 2014-01-17 05:32:22 +00:00
parent 372c577f83
commit 09687c4926
2520 changed files with 34227 additions and 7318 deletions

View file

@ -1,3 +1,10 @@
(in-package :common-lisp-user)
;;
;; FLAG -- if using quicklisp, you can get bordeaux-threads loaded up
;; with: (ql:quickload :bordeaux-threads)
;;
(defvar *philosophers* '(Aristotle Kant Spinoza Marx Russell))
(defclass philosopher ()
@ -7,7 +14,7 @@
(meals-left :initarg :meals-left :accessor meals-left-of)))
(defclass fork ()
((lock :initform (make-lock "fork") :reader lock-of)))
((lock :initform (bt:make-lock "fork") :reader lock-of)))
(defun random-normal (&optional (mean 0.0) (sd 1.0))
(do* ((x1 #1=(1- (* 2.0d0 (random 1d0))) #1#)
@ -31,9 +38,9 @@
:right-fork (nth (mod (1+ i) count) forks)
:name name
:meals-left meals)))
(condition (make-condition-variable))
(lock (make-lock "main loop"))
(output-lock (make-lock "output lock")))
(condition (bt:make-condition-variable))
(lock (bt:make-lock "main loop"))
(output-lock (bt:make-lock "output lock")))
(dolist (p philosophers)
(labels ((think ()
(/me "is now thinking")
@ -41,33 +48,33 @@
(/me "is now hungry")
(dine))
(dine ()
(with-lock-held ((lock-of (left-fork-of p)))
(or (acquire-lock (lock-of (right-fork-of p)) nil)
(bt:with-lock-held ((lock-of (left-fork-of p)))
(or (bt:acquire-lock (lock-of (right-fork-of p)) nil)
(progn (/me "couldn't get a fork and ~
returns to thinking")
(release-lock (lock-of (left-fork-of p)))
(bt:release-lock (lock-of (left-fork-of p)))
(return-from dine (think))))
(/me "is eating")
(sleep* (apply #'random-normal dining-time))
(release-lock (lock-of (right-fork-of p)))
(bt:release-lock (lock-of (right-fork-of p)))
(/me "is done eating (~A meals left)"
(decf (meals-left-of p))))
(cond ((<= (meals-left-of p) 0)
(/me "leaves the dining room")
(with-lock-held (lock)
(bt:with-lock-held (lock)
(setq philosophers (delete p philosophers))
(condition-notify condition)))
(bt:condition-notify condition)))
(t (think))))
(/me (control &rest args)
(with-lock-held (output-lock)
(bt:with-lock-held (output-lock)
(write-sequence (string (name-of p)) e)
(write-char #\Space e)
(apply #'format e (concatenate 'string control "~%")
args))))
(make-thread #'think)))
(loop (with-lock-held (lock)
(bt:make-thread #'think)))
(loop (bt:with-lock-held (lock)
(when (endp philosophers)
(format e "all philosophers are done dining~%")
(return)))
(with-lock-held (lock)
(condition-wait condition lock)))))
(bt:with-lock-held (lock)
(bt:condition-wait condition lock)))))

View file

@ -1,20 +1,19 @@
import std.stdio, std.algorithm, std.string, std.parallelism,
core.sync.mutex;
core.sync.mutex;
void eat(in uint i, in string name, Mutex[] forks) {
void eat(in size_t i, in string name, Mutex[] forks) {
writeln(name, " is hungry.");
immutable j = (i + 1) % forks.length;
// Take forks i and j. The lower one first to prevent deadlock.
auto fork1 = forks[min(i, j)];
auto fork2 = forks[max(i, j)];
fork1.lock();
scope(exit) fork1.unlock();
fork1.lock;
scope(exit) fork1.unlock;
fork2.lock();
scope(exit) fork2.unlock();
fork2.lock;
scope(exit) fork2.unlock;
writeln(name, " is eating.");
writeln(name, " is full.");
@ -25,16 +24,16 @@ void think(in string name) {
}
void main() {
const philosophers = "Aristotle Kant Spinoza Marx Russell".split();
const philosophers = "Aristotle Kant Spinoza Marx Russell".split;
Mutex[philosophers.length] forks;
foreach (ref fork; forks)
fork = new Mutex();
fork = new Mutex;
defaultPoolThreads = forks.length;
foreach (i, philo; taskPool.parallel(philosophers)) {
foreach (_; 0 .. 100) {
foreach (immutable _; 0 .. 100) {
eat(i, philo, forks);
think(philo);
philo.think;
}
}
}

View file

@ -0,0 +1,56 @@
import groovy.transform.Canonical
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
@Canonical
class Fork {
String name
Lock lock = new ReentrantLock()
void pickUp(String philosopher) {
lock.lock()
println " $philosopher picked up $name"
}
void putDown(String philosopher) {
lock.unlock()
println " $philosopher put down $name"
}
}
@Canonical
class Philosopher extends Thread {
Fork f1
Fork f2
@Override
void run() {
def random = new Random()
(1..20).each { bite ->
println "$name is hungry"
f1.pickUp name
f2.pickUp name
println "$name is eating bite $bite"
Thread.sleep random.nextInt(300) + 100
f2.putDown name
f1.putDown name
}
}
}
void diningPhilosophers(names) {
def forks = (1..names.size()).collect { new Fork(name: "Fork $it") }
def philosophers = []
names.eachWithIndex{ n, i ->
def (i1, i2) = [i, (i + 1) % 5]
if (i2 < i1) (i1, i2) = [i2, i]
def p = new Philosopher(name: n, f1: forks[i1], f2: forks[i2])
p.start()
philosophers << p
}
philosophers.each { it.join() }
}
diningPhilosophers(['Aristotle', 'Kant', 'Spinoza', 'Marx', 'Russell'])

View file

@ -0,0 +1,55 @@
class Fork {
has $!lock = Lock.new;
method grab($who, $which) {
remark "$who grabbing $which fork";
$!lock.lock;
}
method drop($who, $which) {
remark "$who dropping $which fork";
$!lock.unlock;
}
}
class Lollipop {
has $!channel = Channel.new;
method mine($who) { $!channel.send($who) }
method yours { $!channel.receive }
}
my $out = Channel.new;
sub remark($msg) { $out.send($msg) }
start { loop { $out.receive.say } }
sub dally($sec) { sleep 0.01 + rand * $sec }
sub MAIN(*@names) {
@names ||= <Aristotle Kant Spinoza Marx Russell>;
my @lfork = Fork.new xx @names;
my @rfork = @lfork.rotate;
my $lollipop = Lollipop.new;
start { $lollipop.yours; }
my @philosophers = do for @names Z @lfork Z @rfork -> $n, $l, $r {
start {
sleep 1 + rand*4;
loop {
$l.grab($n,'left');
dally 1; # give opportunity for deadlock
$r.grab($n,'right');
remark "$n eating";
dally 10;
$l.drop($n,'left');
$r.drop($n,'right');
$lollipop.mine($n);
sleep 1; # lick at least once
remark "$n lost lollipop to $lollipop.yours(), now digesting";
dally 20;
}
}
}
await @philosophers;
}

View file

@ -0,0 +1,40 @@
#!/usr/bin/perl
use common::sense;
use Coro;
use AnyEvent;
use Coro::AnyEvent;
use EV;
my @philosophers = qw(Aristotle Kant Spinoza Marx Russell);
my @forks = (1..@philosophers);
my @fork_sem;
$fork_sem[$_] = new Coro::Semaphore for (0..$#philosophers);
for(my $i = $#philosophers; $i >= 0; $i--){
say $philosophers[$i] . " has fork #" . $forks[$i] . " and fork #" . $forks[$i-1];
async {
my ($name, ,$no, $forks_got) = (@_);
$Coro::current->{desc} = $name;
Coro::AnyEvent::sleep(rand 4);
while(1){
say $name . " is hungry.";
$$forks_got[$no]->down();
Coro::AnyEvent::sleep(rand 1); #Let's make deadlock!
$$forks_got[$no-1]->down();
say $name . " is eating.";
Coro::AnyEvent::sleep(1 + rand 8);
$$forks_got[$no]->up();
$$forks_got[$no-1]->up();
say $name . " is thinking.";
Coro::AnyEvent::sleep(1 + rand 8);
}
}($philosophers[$i], $i, \@fork_sem);
}
EV::loop;

View file

@ -0,0 +1,48 @@
/*REXX prm demonstrates a solution to solve dining philosophers problem.*/
parse arg seed diners /*get optional arguments from CL.*/
if seed\=='' & seed\==',' then call random ,, seed /*for repeatability*/
if diners='' then diners='Aristotle,Kant,Spinoza,Marx,Russell'
tell=left(seed,1)\=='+' /*Leading + in SEED? No stats.*/
diners=translate(diners,,',') /*change a commatized diners list*/
#=words(diners); @.=0 /*the number of dining philospers*/
eatL=15; eatH= 60 /*min & max minutes for eating. */
thinkL=30; thinkH=180 /* " " " " " thinking.*/
forks.=1 /*indicate all forks are on table*/
do tic=1 /*use minutes as time advancement*/
call grabForks /*see if anybody can grab 2 forks*/
call passTime /*handle diners eating | thinking*/
end /*tic*/ /* ··· and time marches on ··· */
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────FORK subroutine─────────────────────*/
fork: parse arg x 1 ox; x=abs(x); L=x-1; if L==0 then L=# /*boundry ? */
if ox<0 then do; forks.L=1; forks.x=1; return; end /*drop forks*/
got2=forks.L & forks.x /*did we get two forks or not? */
if got2 then do; forks.L=0; forks.x=0; end /*got forks.*/
return got2 /*return with success or failure.*/
/*──────────────────────────────────GRABFORKS subroutine────────────────*/
grabForks: do person=1 for # /*see if any person can grab two.*/
if @.person.status\==0 then iterate /*diner ain't waiting*/
if \fork(person) then iterate /*diner didn't grab 2*/
@.person.status='eating' /*diner now chomps on spaghetti. */
@.person.dur=random(eatL,eatH) /*how long will diner eat? */
end /*person*/
return
/*──────────────────────────────────PASSTIME subroutine─────────────────*/
passTime: if tell then say /*show a (blank line) separator. */
do p=1 for # /*process each diner's activity. */
if tell then say right(tic,9,'.') right(word(diners,p),20),
right(word(@.p.status 'waiting',1+(@.p.status==0)),9) right(@.p.dur,5)
if @.p.dur==0 then iterate /*diner is waiting for two forks.*/
@.p.dur=@.p.dur-1 /*indicate 1 timeUnit has gone by*/
if @.p.dur\==0 then iterate /*Activity done? No, keep it up.*/
select /*handle the activity being done.*/
when @.p.status=='eating' then do /*now, leave the table.*/
call fork -p /*drop the forks.*/
@.p.status='thinking' /*status.*/
@.p.dur=random(thinkL,thinkH)
end
when @.p.status=='thinking' then @.p.status=0 /*──► table*/
otherwise nop /*diner must be waiting on forks.*/
end /*select*/
end /*p*/
return