• Lösung b) semaphore mutex ; semaphore s e r v e ; semaphore s h a r e j ; number : array [ 0 . . . n−1] o f i n t e g e r ; repeat P( mutex ) ; number [ i ]:= max( 0 , number [ 1 ] , . . . , number [ n−1])+1; V( mutex ) ; P( s h a r e j ) ; f o r j :=0 to n−1 do begin while number [ j ]!=0 and number [ j ]
– Wenn ein Philosoph essen will, versucht er die Gabeln <strong>zu</strong> beiden Seiten seines Tellers <strong>zu</strong> bekommen. Schat er es, kann er für eine Zeit lang essen. Ist er mit Essen fertig, legt er die Gabeln wieder auf den Tisch <strong>zu</strong>rück und denkt weiter nach. – Frage: Wie kann ein Programm aussehen, bei dem alle Philosophen immer mal wieder essen können und keiner am Tisch verhungert. • Lösungsansatz 1: Der naheliegendste Versuch ist, einen hungrigen Philosophen <strong>zu</strong>erst nach seiner linken Gabel greifen <strong>zu</strong> lassen. Sobald er die linke Gabel hat, greift er nach der rechten Gabel. Das Problem bei einer solchen Vorgehensweise ist dass wenn alle Philosophen gleichzeitig ihre linke Gabel schnappen, kommt es <strong>zu</strong> einer Verklemmung, einem Deadlock, und es geht nicht weiter. Eine modizierte Version dieser Vorgehensweise ist, dass ein hungriger Philosoph <strong>zu</strong>erst seine linke Gabel nimmt und dann prüft, ob die rechte Gabel verfügbar ist. Ist dies der Fall, kann er sie nehmen. Wenn nicht, legt er seine linke Gabel wieder <strong>zu</strong>rück und wiederholt den Vorgang nach einer gewissen Zeit. Auch dieses Vorgehen kann <strong>zu</strong> einem Problem führen. Wenn alle Philosophen im Gleichtakt vorgehen, kommt es <strong>zu</strong> einem Lifelock. • Lösungsansatz 2: Bei einem Lifelock nimmt jeder Philosoph seine linke Gabel, stellt fest, dass die rechte Gabel nicht frei ist und legt die linke <strong>zu</strong>rück und so weiter. In einer solchen Situation laufen die Prozesse zwar, aber sie kommen nicht in ihrer Abarbeitung weiter. Man spricht hier auch vom Aushungern. Eine Möglichkeit, die <strong>zu</strong>mindest meistens funktioniert ist, dass die Philosophen eine nicht eine feste, sondern eine <strong>zu</strong>fällig lange Zeit warten, bis sie den Vorgang wiederholen. So ist die Möglichkeit eines Lifelock sehr gering, aber es kann dennoch zeitweise <strong>zu</strong> einem Aushungern kommen. Eine funktionierende Möglichkeit ist, dass man das Aufnehmen der Gabeln, Essen und Ablegen der Gabeln als kritischen Abschnitt ansehen und unter gegenseitigem Ausschluss ablaufen lässt. In diesem Fall darf immer nur ein Philosoph essen, obwohl die Bestecke für zwei gleichzeitig essende Philosophen reichen würden • Lösungsansatz 3: Eine Lösung, bei der immer zwei Philosophen essen können und weder Deadlocks noch Lifelocks entstehen können, ist wie folgt: In einem Feld wird verfolgt, ob ein Philosoph gerade nachdenkt, isst oder hungrig ist, also versucht die Gabeln <strong>zu</strong> bekommen. Ein Philosoph kann nur in den Zustand essen übergehen, wenn seine beiden Nachbarn gerade nicht am Essen sind. Es existiert pro Philosoph ein Semaphor, so dass hungrige Philosophen blockieren können, falls die benötigten Gabeln in Gebrauch sind. Erst gelangt ein hungriger Philosoph alleine in den kritischen Bereich. Er prüft, ob seine beiden Nachbarn essen. Falls ja, blockiert er solange. Falls nein, beginnt er <strong>zu</strong> essen und verlässt den kritischen Bereich. Ist er fertig mit Essen, muss er in den kritischen Bereich kommen, seinen Status auf nachdenken setzen, die Gabeln freigeben und den kritischen Bereich verlassen. #d e f i n e N 5 /∗ Number o f p h i l o s p h e r s ∗/ #d e f i n e RIGHT( i ) ( ( ( i )+1) %N) #d e f i n e LEFT( i ) ( ( ( i )==N) 0 : ( i )+1) typedef enum { THINKING, HUNGRY, EATING } p h i l s t a t e ; p h i l s t a t e s t a t e [N ] ; semaphore mutex =1; semaphore s [N ] ; /∗ one per philosopher , a l l 0 ∗/ void t e s t ( i n t i ) { i f ( s t a t e [ i ] == HUNGRY && s t a t e [LEFT( i ) ] != EATING && s t a t e [RIGHT( i ) ] != EATING ) { s t a t e [ i ] = EATING; V( s [ i ] ) ; } }