Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- A1
- (a)
- Die Prozesse müssen sich im gegebenen Schema stets abwechseln. Stürzt z.B P1 in remainderSection(P1) ab, so kann P0 noch ein mal durchgeführt werden, danach aber nie wieder, da P1 ausgeführt werden müsste, um turn wieder auf 0 zu setzen. Damit ist die Bedingung "Progress" verletzt, da in diesem Szenario P0 nicht wieder ausgeführt wird, aber dies nicht durch die Bevorzugung anderer Prozesse zustandekommt.
- (b)
- Dieses Verfahren garantiert nicht die Bedingung "Mutual exclusion", was an folgendem Beispiel ersichtlich wird:
- Es wird zunächst P0 ausgeführt, bis turn = 1 gesetzt wird und wird dann unterbrochen. Dann wird P1 ausgeführt, bis turn = 0 gesetzt wird. Nun wird wieder P0 ausgeführt, aber in remainderSection() wieder unterbrochen (d.h. alive[0] = 0) und P1 wieder fortgesetzt und erreicht den kritischen Bereich (da alive[0] = 0) und wird unterbrochen (weiterhin ist turn = 0). Nun wird P0 wieder ausgeführt, und da turn = 0 ist, darf P0 auch den kritischen Bereich betreten, obwohl P1 ebenfalls darin ist.
- (c)
- Hier wird "Bounded Waiting" verletzt. Es ist nämlich nicht garantiert, dass ein Prozess jemals den kritischen Bereich betreten darf. Dazu ein Beispiel: P0 wird immer nach dem Setzen des Locks unterbrochen und P1 ausgeführt, danach wieder P0 bis zum Erneuten Setzen des Locks. Dann kann P1 nie den kritischen Bereich betreten, P0 aber beliebig oft. Somit ist es nicht garantiert, dass P1 nur endlich lange bis zur Ausführung des kritischen Bereiches warten muss.
- A2
- (a)
- Es liegt ein möglicher Deadlock vor, denn der Verbraucher kann den kritischen Bereich sperren, obwohl er nichts tun kann, da N = 0 vorliegt. Nun kann aber auch kein Erzeuger mehr in den kritischen Bereich, da ein Verbraucher diesen sperrt, d.h. es kann kein Gut für den Verbrauch erzeugt werden, sodass der Verbraucher den kritischen Bereich nie wieder verlässt. Dies kann behoben weden, indem die Reihenfolge der wait()-Befehle des Verbrauchers getauscht werden, denn dann betritt dieser nur den kritischen Bereich, wenn auch etwas zum Verbrauch vorhanden ist und er folglich den kritischen Bereich auch wieder verlässt.
- (b)
- queue q_einw;
- int automat_lock = 0; //Test-Set-Lock-Variable für Synchronisierung des Ticket-Ziehens
- int m; //Anzahl der Schalter
- init(M, m); //Erstelle Zählsemaphore für die Schalter
- EINWOHNER
- pid = getpid();
- while(tsl(&automat_lock) != 0){
- noop;
- }
- pushback(q_einw,pid);
- automat_lock = 0;
- sleep();
- macheAmtZeug();
- signal(M);
- AUFRUFANLAGE
- while(true){ //Anders als normale Ämter arbeiten wir IMMER
- wait(M); //Warte auf freien Schalter
- if(size(q_einw) > 0){
- //Falls noch Einwohner abzuarbeiten sind, machen wir das
- next = popfront(q_einw);
- wakeup(next);
- }
- }
- (c)
- queue q_einw;
- queue q_mutter;
- int automat_lock = 0; //Test-Set-Lock-Variable für Synchronisierung des Ticket-Ziehens
- int automat_mutter_lock = 0;
- int m; //Anzahl der Schalter
- init(M, m); //Erstelle Zählsemaphore für die Schalter
- MUTTER m. N.
- pid = getpid();
- while(tsl(&automat_mutter_lock) != 0){
- noop;
- }
- pushback(q_mutter,pid);
- automat_mutter_lock = 0;
- sleep();
- macheAmtZeug();
- signal(M);
- EINWOHNER (KEINE MUTTER)
- pid = getpid();
- while(tsl(&automat_lock) != 0){
- noop;
- }
- pushback(q_einw,pid);
- automat_lock = 0;
- sleep();
- macheAmtZeug();
- signal(M);
- AUFRUFANLAGE
- while(true){ //Anders als normale Ämter arbeiten wir IMMER
- wait(M); //Warte auf freien Schalter
- if(size(q_mutter) > 0){
- //Falls noch Mutternde abzuarbeiten sind, machen wir das
- next = popfront(q_mutter);
- wakeup(next);
- } else if(size(q_einw) > 0){
- //Falls noch Einwohner abzuarbeiten sind, machen wir das
- next = popfront(q_einw);
- wakeup(next);
- }
- }
- (d)
- Durch den Einsatz von Zählsemaphoren mit assoziierten Queues müssen die Semaphore und die Queue aus (b) nicht einzeln verwaltet werden, sondern können direkt über die jeweiligen Befehle zugleich gemanagt werden (was potentielle Fehlerquellen und Implementierungsaufwand verringert).
- A3
- (a)
- Semaphore sind Konstrukte, die i.d.R. aus einer int-Variable sowie gewissen Funktionen, die diese Variable verändern/ausgeben bestehen. Dabei steht die int-Variable für die Anzahl der verfügbaren Betriebsmittel eines gewissen Typs; die Funktionen repräsentieren das Reservieren/Freigeben dieser Mittel, sodass Semaphore zur Synchronisierung des Zugriffs auf Betriebsmittel genutzt werden.
- (b)
- init() - erzeugt eine neue Semaphore und definiert die Anzahl der zur Verfügung stehenden Betriebsmittel durch das übergebene Argument
- wait() - testet, ob Betriebsmittel vorhanden sind und wartet ggf. ab, bis dies der Fall ist.
- signal() - erhöht den Wert der Semaphore und signalisiert so das Freigeben eines Betriebsmittels
- destroy() - Vernichtet die Semaphore (Ohne Warten auf die Freigabe durch die benutzenden Prozesse, was zu undefiniertem Verhalten führen kann!)
- A4
- siehe Sourcefiles
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement