# Distributed Dining Philosophers. Based on the example in Section 13.3 of # "The SR Programming Language: Concurrency in Practice", by Greg Andrews and # Ron Olsson, Benjamin/Cummings, 1993. The algorithm is from Chandy and Misra, # "Drinking Philosophers Problem", ACM TOPLAS v 6, n 4, Oct 1984, pp 632-646. # Usage: a.out [n secs t_secs e_secs t_secs e_secs ...] # (for n philosophers, secs seconds running time, t_secs max thinking seconds, # e_secs max eating seconds for each philosopher) # resource Philosopher import Servant, MPDanimator body Philosopher(cap Servant myservant, int id, int thinking, int eating) process phil { while (true) { nap(int(random(thinking))) write(age(), "philosopher", id, "is hungry") # Change a hungry philosopher's symbol to be solid green. call A_color(id, "green") call A_fill(id, "solid") myservant.getforks() # Change an eating philosopher's symbol to be solid blue. call A_color(id, "blue") nap(int(random(eating))) # Change a thinking philosopher's symbol to an outline black circle. call A_fill(id, "outline") call A_color(id, "black") myservant.relforks() } } end Philosopher resource Servant import MPDanimator op getforks(), relforks() op needR(), needL(), passR(), passL() op links(cap Servant r, cap Servant l) op forks(bool haveR, bool dirtyR, bool haveL, bool dirtyL) # This op and the variables below are used to hold the symbol id numbers of # the left and right fork symbols and where the left and right forks are # placed next to the philosopher when it possesses them. op fork_ids(int forkR, int forkL, int holderR, int holderL ) body Servant(int id) op hungry(), eat() cap Servant r, l bool haveR, dirtyR, haveL, dirtyL int forkR, forkL, holderR, holderL proc getforks() { send hungry(); receive eat() } process server { receive links(r, l) receive forks(haveR, dirtyR, haveL, dirtyL) # Move a left or right fork initially given to this philosopher to be next # to the philosopher. receive fork_ids(forkR, forkL, holderR, holderL) if (haveR) { call A_jumpto(forkR, holderR) } if (haveL) { call A_jumpto(forkL, holderL) } if (dirtyR) { call A_color(forkR, "orange") call A_fill(forkR, "solid") } if (dirtyL) { call A_color(forkL, "orange") call A_fill(forkL, "solid") } while (true) { in hungry() -> if (~haveR) { send r.needL() } else { write(age(), "philosopher", id, "has right fork") } if (~haveL) { send l.needR() } else { write(age(), "philosopher", id, "has left fork") } while (~(haveR & haveL)) { in passR() -> haveR = true; dirtyR = false write(age(), "philosopher", id, "got right fork") # Move the fork from where it was to be next to this philosopher and then # change its symbol to be a black outline circle i.e. not dirty. Also raise # the fork's symbol to the closest viewing plane to make it more visible. call A_stepjumpto(forkR, holderR, 5, 100) call A_fill(forkR, "outline") call A_color(forkR, "black") call A_raise(forkR) [] passL() -> haveL = true; dirtyL = false write(age(), "philosopher", id, "got left fork") # Ditto. call A_stepjumpto(forkL, holderL, 5, 100) call A_fill(forkL, "outline") call A_color(forkL, "black") call A_raise(forkL) [] needR() st dirtyR -> haveR = false; dirtyR = false send r.passL(); send r.needL() write(age(), "philosopher", id, "sends dirty right fork") [] needL() st dirtyL -> haveL = false; dirtyL = false send l.passR(); send l.needR() write(age(), "philosopher", id, "sends dirty left fork") ni } write(age(), "philosopher", id, "has both forks") send eat(); dirtyR = true; dirtyL = true receive relforks() write(age(), "philosopher", id, "is finished eating") # Now that the philosopher has finished eating, its forks are dirty so # change their symbols to be solid orange circles. call A_color(forkL, "orange") call A_fill(forkL, "solid") call A_color(forkR, "orange") call A_fill(forkR, "solid") [] needR() -> haveR = false; dirtyR = false; send r.passL() write(age(), "philosopher", id, "sends right fork") [] needL() -> haveL = false; dirtyL = false; send l.passR() write(age(), "philosopher", id, "sends left fork") ni } } end Servant resource Main() import Philosopher, Servant, MPDanimator int n = 5; getarg(1, n) int runtime = 60; getarg(2, runtime) cap Servant s[1:n] cap Philosopher p[1:n] int think[1:n] = ([n] 5) int eat[1:n] = ([n] 2) for [ i = 1 to n ] { getarg(2*i+1, think[i]); getarg(2*i+2, eat[i]) } write(n, "philosophers; think, eat times in seconds:") for [ i = 1 to n ] { writes(" ", think[i]) }; write() for [ i = 1 to n ] { writes(" ", eat[i]) }; write() ##### animator #####v # Change coordinates so 0,0 is the center, then create a big black outline # circle to be the table. call A_coords(-1.5, -1.5, 1.5, 1.5) call A_circle(1000, 0.0, 0.0, 1.0, "black", "outline") # Put some annotated symbols on the screen. call A_circle(1001, -1.4, -0.6, 0.02, "black", "outline") call A_text(1002, -1.3, -0.625, 0, "black", "clean fork") call A_circle(1003, -1.4, -0.8, 0.02, "orange", "solid") call A_text(1004, -1.3, -0.825, 0, "black", "dirty fork") call A_circle(1005, -1.4, -1.0, 0.05, "black", "outline") call A_text(1006, -1.3, -1.025, 0, "black", "THINKING") call A_circle(1007, -1.4, -1.2, 0.05, "green", "solid") call A_text(1008, -1.3, -1.225, 0, "black", "HUNGRY") call A_circle(1009, -1.4, -1.4, 0.05, "blue", "solid") call A_text(1010, -1.3, -1.425, 0, "black", "EATING") # Put a clean set of forks, small black outline circles, near the table. call A_text(1011, -1.0+0.05*(n+1), -1.41, 0, "black", "forks") for [ i = 1 to n ] { call A_circle(3000+i-1, -1.0+0.05*i, -1.4, 0.02, "black", "outline") } const real TWO_PI = 2.0*acos(-1.0) for [ i = 1 to n ] { # Put the philosophers, black outline circles, around the table. call A_circle(i, sin(i*(TWO_PI/n)), cos(i*(TWO_PI/n)), 0.1, "black", "outline") call A_text(2000+i, sin(i*(TWO_PI/n))+0.1, cos(i*(TWO_PI/n))+0.1, 1, "black", string(i)) # Put nearly invisible circles (points) on the left and right side of each # philosopher to be places the forks can be moved to when the philosopher # gets possession of a fork. call A_circle(4000+2*i, sin(i*(TWO_PI/n)-0.12), cos(i*(TWO_PI/n)-0.13), 0.001, "black", "outline") call A_circle(4000+2*i+1, sin(i*(TWO_PI/n)+0.12), cos(i*(TWO_PI/n)+0.13), 0.001, "black", "outline") } for [ i = 1 to n ] { s[i] = create Servant(i) create Philosopher(s[i], i, 1000*think[i], 1000*eat[i]) } for [ i = 1 to n ] { send s[i].links(s[((i-2) mod n)+1], s[(i mod n)+1]) } send s[1].forks(true, true, true, true) for [ i = 2 to n-1 ] { send s[i].forks(false, false, true, false) } send s[n].forks(false, false, false, false) # Send to each philosopher the xtango animator symbol id's of the two forks # the philosopher needs to eat and the places where possessed forks are to # be moved next to the philosopher. for [ i = 1 to n ] { send s[i].fork_ids(3000+((i-1) mod n), 3000+(i mod n), 4000+2*i, 4000+2*i+1) } nap(1000*runtime); write("must stop now"); call A_end(); stop end Main