经常使用的方法:
Locking a resource is a common technique to ensure the resource is accessed by only one program or chunk of code
at a time.
算法:
Waiter solution
引入一个服务员 Philosophers must ask his permission before taking up any forks. Because the waiter is aware of
which forks are in use, he is able to arbitrate and prevent deadlock.
//这个方法的关键是引入了一个全局监视变量,可以轻松完成监控分配。
Resource hierarchy solution
Another simple solution is achieved by assigning a partial order, or hierarchy, to the resources (the forks, in
this case), and establishing the convention that all resources will be requested in order, and released in reverse
order, and that no two resources unrelated by order will ever be used by a single unit of work at the same time.
This is often the most practical solution for real world Computer Science problems; by assigning a constant
hierarchy of locks, and by enforcing the ordering of obtaining the locks this problem can be avoided.
//这个解法的关键在于引入了偏序关系,之后的很多事情变得很简单了。
Chandy / Misra solution
1 For every pair of philosophers contending for a resource, create a fork and give it to the philosopher with the
lower ID. Each fork can either be dirty or clean. Initially, all forks are dirty.
2 When a philosopher wants to use a set of resources (i.e. eat), he must obtain the forks from his contending
neighbors. For all such forks he does not have, he sends a request message.
3 When a philosopher with a fork receives a request message, he keeps the fork if it is clean, but gives it up
when it is dirty. If he sends the fork over, he cleans the fork before doing so.
4 After a philosopher is done eating, all his forks become dirty. If another philosopher had previously requested
one of the forks, he cleans the fork and sends it.
//不断在状态更迭中转换标记状态。很奇妙的一个东西。。
code:
PROGRAM d_p;
CONST
DoomsDay = FALSE;
MONITOR dining_philosophers; // initialize use of monitors
CONST
Eating = 0;
Hungry = 1;
Thinking = 2;
VAR
i : INTEGER; // init loop variable
state : ARRAY [0..4] OF INTEGER; // Eating, Hungry, Thinking
self : ARRAY [0..4] OF CONDITION; // one for each Philospher
// place for Hungry Ph to wait until chopsticks become available
PROCEDURE test(k : INTEGER);
// if k's left & right neighbors aren't Eating & k is Hungry
// then change k's state to Eating & signalc (in case k is waitc-ing)
BEGIN
IF (state[(k+4) MOD 5] <> Eating) AND (state[k] = Hungry) AND
(state[(k+1) MOD 5] <> Eating) THEN {right neighbor}
BEGIN
state[k] := eating;
SIGNALC(self[k]); //tell k to eat if k is waitc-ing
END;
END;
PROCEDURE pickup(i: INTEGER);
BEGIN
state[i] := Hungry;
WRITELN('philosopher ',i,' hungry');
test(i); // are my neighbors eating?
IF state[i] <> Eating THEN // waitc if they are (sleep mode)
WAITC(self[i]);
WRITELN('philosopher ',i,' eating');
END;
PROCEDURE putdown(i : INTEGER);
BEGIN
state[i] := Thinking;
WRITELN('philosopher ',i,' thinking');
test( (i+4) MOD 5); // give left neighbor chance to eat
test( (i+1) MOD 5); // give right neighbor chance to eat
END;
BEGIN // monitor initialization
FOR i := 0 TO 4 DO state[i] := Thinking;
END; // dining_philosopher monitor
PROCEDURE philosopher(i : INTEGER);
BEGIN
REPEAT
pickup(i); // pick up chopsticks
putdown(i); // put down chopsticks
UNTIL DoomsDay;
END;
BEGIN
COBEGIN // process to being all five processes at once
philosopher(0); philosopher(1); philosopher(2);
philosopher(3); philosopher(4);
COEND;
END