This commit is contained in:
Ingy döt Net 2013-04-10 21:29:02 -07:00
parent 764da6cbbb
commit db842d013d
19005 changed files with 197040 additions and 7 deletions

View file

@ -0,0 +1,21 @@
let random_wait n = Unix.sleep (Random.int n);;
let print s m = Printf.printf "philosopher %s is %s\n" s m; flush(stdout);;
let will_eat s = print s "eating"; random_wait 10;;
let will_think s = print s "thinking"; random_wait 20; print s "hungry";;
(* a,b,c,d,e are thinking philosophers; ah,bh,ch,dh,eh are the same philosophers when hungry;
fab is the fork located between philosophers a and b; similarly for fbc, fcd, ... *)
def ah() & fab() & fea() = will_eat "Aristotle"; a() & fab() & fea()
or bh() & fab() & fbc() = will_eat "Kant"; b() & fab() & fbc()
or ch() & fbc() & fcd() = will_eat "Spinoza"; c() & fbc() & fcd()
or dh() & fcd() & fde() = will_eat "Marx"; d() & fcd() & fde()
or eh() & fde() & fea() = will_eat "Russell"; e() & fde() & fea()
and a() = will_think "Aristotle"; ah()
and b() = will_think "Kant"; bh()
and c() = will_think "Spinoza"; ch()
and d() = will_think "Marx"; dh()
and e() = will_think "Russell"; eh()
;;
spawn fab() & fbc() & fcd() & fde() & fea() & a() & b() & c() & d() & e();;

View file

@ -0,0 +1,47 @@
let print s t m = Printf.printf "t=%d: philosopher %s is %s\n" t s m; flush(stdout);;
let random_wait n = Unix.sleep (Random.int n);;
(* auxiliary function to keep track of time ticks, using integer seconds *)
def ts () & counter(n) = counter(n) & reply n to ts
or update_counter() & counter(n) = counter(n+1) & reply to update_counter
and counter_sentinel() = Unix.sleep 1; update_counter(); counter_sentinel()
;;
spawn counter(0) & counter_sentinel();;
def stats(n, waited, maxwaited) & report_wait_time(m) =
let (n', waited', maxwaited') = (n+1, waited+m, max maxwaited m) in
Printf.printf "waiting average %f, max waited %d\n"
(float_of_int waited' /. float_of_int n')
maxwaited';
flush(stdout);
stats(n',waited',maxwaited') & reply () to report_wait_time
;;
spawn stats(0,0,0);;
let eat s t = print s t "eating"; random_wait 10;;
let think s = print s (ts()) "thinking"; random_wait 20;;
(* "p" will be a philosopher channel, to be defined later
the messages ah, bh, ... do not need to be injected now. *)
let will_eat s t = let t' = ts() in report_wait_time(t'-t); eat s t';;
def ah(t,p) & fab() & fea() = will_eat "Aristotle" t; p() & fab() & fea()
or bh(t,p) & fab() & fbc() = will_eat "Kant" t; p() & fab() & fbc()
or ch(t,p) & fbc() & fcd() = will_eat "Spinoza" t; p() & fbc() & fcd()
or dh(t,p) & fcd() & fde() = will_eat "Marx" t; p() & fcd() & fde()
or eh(t,p) & fde() & fea() = will_eat "Russell" t; p() & fde() & fea()
;;
spawn fab() & fbc() & fcd() & fde() & fea();;
(* define the thinking -> hungry transitions using local philosophers, and inject the philosophers *)
List.map
(fun (h,s) -> def p() = think s; let t = ts() in print s t "hungry"; h(t,p) in spawn p())
[(ah,"Aristotle"); (bh,"Kant"); (ch,"Spinoza"); (dh,"Marx"); (eh,"Russell")]
;;
(* this replaces repetitive code such as that shown in the previous solution *)
(* now we need to wait and do nothing; nobody will be able to inject godot() *)
def wait_forever() & godot() = reply () to wait_forever in wait_forever();;

View file

@ -0,0 +1,77 @@
#!/usr/bin/jocamlrun jocaml
(* eating and thinking between 0 and this-1 *)
let eating_max_interval = 10;;
let thinking_max_interval = 10;;
let number_of_philosophers = 5;;
let random_wait n = Unix.sleep (Random.int n);;
(* counter for unique timestamp, not related to time in seconds *)
def get_current_time () & unique_ts_counter(n) = unique_ts_counter(n+1) & reply n to get_current_time;;
spawn unique_ts_counter(0);;
(* functions that wait and print diagnostics *)
let name i = List.nth ["Aristotle"; "Kant"; "Spinoza"; "Marx"; "Russell"] i;;
let message i m = Printf.printf "philosopher %s is %s\n" (name i) m; flush(stdout);;
let eat i = message i "eating"; random_wait eating_max_interval;;
let think i = message i "thinking"; random_wait thinking_max_interval;;
type philosopher_state_t = Eating | Hungry of int | Thinking;;
(* initial states *)
let states = Array.make number_of_philosophers Thinking;;
(* one philosopher's processes *)
let make_philosopher i got_hungry done_eating =
def hungry() & forks() = eat i ; done_eating(i) & thinking()
and thinking() = think i; got_hungry(i) & hungry()
in spawn thinking(); forks
;;
(* deciding who will eat first *)
let next_phil i = (i+1) mod number_of_philosophers;;
let prev_phil i = (number_of_philosophers+i-1) mod number_of_philosophers;;
let is_hungry p = match p with
| Hungry h -> true
| _ -> false;;
let not_eating p = match p with
| Eating -> false
| _ -> true;;
let is_more_hungry p q = match q with
| Hungry hj -> (
match p with
| Hungry hi -> hi <= hj
| _ -> false
)
| _ -> true
;;
let may_eat_first i =
is_hungry states.(i)
&& not_eating states.(next_phil i) && not_eating states.(prev_phil i)
&& is_more_hungry states.(i) states.(next_phil i)
&& is_more_hungry states.(i) states.(prev_phil i);;
let decide_eating i =
if (may_eat_first i) then (states.(i) <- Eating; true)
else false;;
def waiter(all_forks) & got_hungry(i) =
states.(i) <- Hungry (get_current_time());
let will_eat = decide_eating i in (
waiter(all_forks) & (if will_eat then all_forks.(i)() else 0)
)
or waiter(all_forks) & done_eating(i) =
states.(i) <- Thinking;
let next_will_eat = decide_eating (next_phil i) in
let prev_will_eat = decide_eating (prev_phil i) in (
waiter(all_forks)
& (if next_will_eat then all_forks.(next_phil i)() else 0)
& (if prev_will_eat then all_forks.(prev_phil i)() else 0)
);;
let all_forks = Array.init number_of_philosophers (fun i -> make_philosopher i got_hungry done_eating)
in spawn waiter(all_forks);;
(* now we need to wait and do nothing; nobody will be able to inject godot() *)
def wait_forever() & godot() = reply () to wait_forever in wait_forever();;

View file

@ -0,0 +1,156 @@
:- category(chopstick).
% chopstick actions (picking up and putting down) are synchronized using a notification
% such that a chopstick can only be handled by a single philosopher at a time:
:- public(pick_up/0).
pick_up :-
threaded_wait(available).
:- public(put_down/0).
put_down :-
threaded_notify(available).
:- end_category.
:- object(cs1,
imports(chopstick)).
:- threaded.
:- initialization(threaded_notify(available)).
:- end_object.
:- object(cs2,
imports(chopstick)).
:- threaded.
:- initialization(threaded_notify(available)).
:- end_object.
:- object(cs3,
imports(chopstick)).
:- threaded.
:- initialization(threaded_notify(available)).
:- end_object.
:- object(cs4,
imports(chopstick)).
:- threaded.
:- initialization(threaded_notify(available)).
:- end_object.
:- object(cs5,
imports(chopstick)).
:- threaded.
:- initialization(threaded_notify(available)).
:- end_object.
:- category(philosopher).
:- public(left_chopstick/1).
:- public(right_chopstick/1).
:- public(run/2).
:- private(message/1).
:- synchronized(message/1).
:- uses(random, [random/3]).
run(0, _) :-
this(Philosopher),
message([Philosopher, ' terminated.']).
run(Count, MaxTime) :-
Count > 0,
think(MaxTime),
eat(MaxTime),
Count2 is Count - 1,
run(Count2, MaxTime).
think(MaxTime):-
this(Philosopher),
random(1, MaxTime, ThinkTime),
message(['Philosopher ', Philosopher, ' thinking for ', ThinkTime, ' seconds.']),
thread_sleep(ThinkTime).
eat(MaxTime):-
this(Philosopher),
random(1, MaxTime, EatTime),
::left_chopstick(LeftStick),
::right_chopstick(RightStick),
LeftStick::pick_up,
RightStick::pick_up,
message(['Philosopher ', Philosopher, ' eating for ', EatTime, ' seconds with chopsticks ', LeftStick, ' and ', RightStick, '.']),
thread_sleep(EatTime),
::LeftStick::put_down,
::RightStick::put_down.
% writing a message needs to be synchronized as it's accomplished
% using a combination of individual write/1 and nl/0 calls:
message([]) :-
nl,
flush_output.
message([Atom| Atoms]) :-
write(Atom),
message(Atoms).
:- end_category.
:- object(aristotle,
imports(philosopher)).
left_chopstick(cs1).
right_chopstick(cs2).
:- end_object.
:- object(kant,
imports(philosopher)).
left_chopstick(cs2).
right_chopstick(cs3).
:- end_object.
:- object(spinoza,
imports(philosopher)).
left_chopstick(cs3).
right_chopstick(cs4).
:- end_object.
:- object(marx,
imports(philosopher)).
left_chopstick(cs4).
right_chopstick(cs5).
:- end_object.
:- object(russell,
imports(philosopher)).
left_chopstick(cs1). % change order so that the chopsticks are picked
right_chopstick(cs5). % in different order from the other philosophers
:- end_object.