Presentation is loading. Please wait.

Presentation is loading. Please wait.

More on Classic Synchronization Problems, Monitors, and Deadlock

Similar presentations


Presentation on theme: "More on Classic Synchronization Problems, Monitors, and Deadlock"— Presentation transcript:

1 More on Classic Synchronization Problems, Monitors, and Deadlock
CSCI 3753 Operating Systems Spring 2005 Prof. Rick Han

2 Announcements PA #2 is coming, assigned Tuesday night
Midterm is tentatively Thursday March 10 Read chapters 9 and 10 HW #3 is due Friday Feb. 25, a week+ from now submitting graphic: .doc OK? - will post an answer extra office hours Thursday 1 pm - post this TA finished regrading some HWs that were cut off by moodle Slides on synchronization online user vs kernel level threads slides soon

3 From last time... We discussed semaphores Deadlock
Classic synchronization problems Bounded Buffer Producer/Consumer Problem First Readers/Writers Problem Dining Philosophers Problem

4

5

6 Semaphores Usage example #1: mutual exclusion
Semaphore S = 1; // initial value of semaphore is 1 int counter; // assume counter is set correctly somewhere in code Process P1: P(S); // execute critical section counter++; V(S); Process P2: P(S); // execute critical section counter--; V(S); Both processes atomically P() and V() the semaphore S, which enables mutual exclusion on critical section code, in this case protecting access to the shared variable counter

7 Semaphores Process P1: C1; // execute C1
Usage example #2: enforcing order of access between two processes Suppose there are two processes P1 and P2, where P1 contains code C1 and P2 contains code C2 Want to ensure that code C1 executes before code C2 Use semaphores to synchronize the order of execution of the two processes Semaphore S=0; // initial value of semaphore = 0 Process P1: C1; // execute C1 signal(S); // V() the semaphore Process P2: wait(S); // P() the semaphore C2; // execute C2

8 Semaphores In the previous example #2, there are two cases:
if P1 executes first, then C1 will execute first, then P1 will V() the semaphore, increasing its value to 1 Later, when P2 executes, it will call wait(S), which will decrement the semaphore to 0 followed by execution of C2 Thus C1 executes before C2 If P2 executes first, then P2 will block on the semaphore, which is equal to 0, so that C2 will not be executed yet Later, when P1 executes, it will run through C1, then V() the semaphore This awakens P2, which then executes C2

9 Semaphores Let’s revisit the following intuitive implementation of semaphores that uses only disabling and reenabling of interrupts Note that a process that blocks on this kind of semaphore will spin in a busy wait while() loop - this type of semaphore is called a spinlock Figure 8.25 in the text illustrates a semaphore implemented using a TestandSet instruction that also exhibits spinlock behavior P(S) { disableInterrupts(); while(S==0) { enableInt(); disableInt(); } S--; enableInt() V(S) { disableInt(); S++; enableInt() }

10 Semaphores Spinlock implementations of semaphores can occupy the CPU unnecessarily Instead, sleep the process until it needs to be woken up by a V()/signal() P(semaphore *S) { S->value--; if (S->value<0) { add this process to S->list; block(); } V(semaphore *S) { S->value++; if (S->value<=0) { remove a process P from S->list; wakeup(P); } where we have defined the following structure for a semaphore typedef struct { int value; struct process *list; } semaphore;

11 Semaphores In the previous slide’s redefinition of a semaphore, we are departing from the classic definition of a semaphore Now, the semaphore’s value is allowed to be negative, because the decrement occurs before the test in P() The absolute value of the semaphore’s negative amount can now be used to indicate the number of processes blocked on the semaphore Processes now yield the CPU if the semaphore’s value is negative, rather than busy wait If more than one process is blocked on a semaphore, then use a FIFO queue to select the next process to wake up when a semaphore is V’ed Why is LIFO to be avoided?

12 Deadlock Semaphores provide synchronization, but can introduce more complicated higher level problems like deadlock two processes deadlock when each wants a resource that has been locked by the other process e.g. P1 wants resource R2 locked by process P2 with semaphore S2, while P2 wants resource R1 locked by process P1 with semaphore S1

13 Deadlock Semaphore Q= 1; // binary semaphore as a mutex lock
Semaphore S = 1; // binary semaphore as a mutex lock Process P1: P(S); P(Q); modify R1 and R2; V(S); V(Q); Process P2: P(Q); P(S); modify R1 and R2; V(Q); V(S); (1) (2) (3) (4) Deadlock! If statements (1) through (4) are executed in that order, then P1 and P2 will be deadlocked after statement (4) - verify this for yourself by stepping thru the semaphore values

14 Deadlock In the previous example,
Each process will sleep on the other process’s semaphore the V() signalling statements will never get executed, so there is no way to wake up the two processes from within those two processes there is no rule prohibiting an application programmer from P()’ing Q before S, or vice versa - the application programmer won’t have enough information to decide on the proper order in general, with N processes sharing N semaphores, the potential for deadlock grows

15 Deadlock Other examples:
A programmer mistakenly follows a P() with a second P() instead of a V(), e.g. P(mutex) critical section P(mutex) <---- this causes a deadlock, should have been a V() A programmer forgets and omits the P(mutex) or V(mutex). Can cause deadlock if V(mutex) is omitted. Can violate mutual exclusion if P(mutex) is omitted. A programmer reverses the order of P() and V(), e.g. V(mutex) critical section <---- this violates mutual exclusion, but is not an P(mutex) example of deadlock

16 Classic Synchronization Problems
Bounded Buffer Producer-Consumer Problem Readers-Writers Problem First Readers Problem Dining Philosophers Problem These are not just abstract problems They are representative of several classes of synchronization problems commonly encountered when trying to synchronize access to shared resources among multiple processes

17 Bounded Buffer Producer/Consumer Problem
Pool of n buffers, each capable of holding 1 item producer takes an empty buffer and produces a full buffer consumer takes a full buffer and produces an empty buffer Empty Pool Producer Consumer Full Pool Graphic © Pearson textbook slides

18 Bounded Buffer Producer/Consumer Problem
Synchronization setup: Use a mutex semaphore to protect access to buffer manipulation, mutexinit = 1 Use two counting semaphores full and empty to keep track of the number of full and empty buffers, where the values of full + empty = n fullinit = 0 emptyinit = n

19 Bounded Buffer Producer/Consumer Problem
Why do we need counting semaphores? Why do we need two of them? Consider the following: Producer: while(1) { // need code here to keep track of number of empty buffers P(mutex) obtain empty buffer and add next item, creating a full buffer V(mutex) ... } Consumer: while(1) { ... P(mutex) remove item from full buffer, create an empty buffer V(mutex) }

20 Bounded Buffer Producer/Consumer Problem
If we add an empty counting semaphore initialized to n, then a producer calling P(empty) will keep decrementing until 0, replacing n empty buffers with n full ones. If the producer tries to produce any more, P(empty) blocks producer until more empty buffers are available - this is the proper behavior that we want Producer: while(1) { P(empty) P(mutex) obtain empty buffer and add next item, creating a full buffer V(mutex) ... } Consumer: while(1) { ... P(mutex) remove item from full buffer, create an empty buffer V(mutex) }

21 Bounded Buffer Producer/Consumer Problem
We also need to add V(empty), so that when the consumer is done reading, more empty buffers are produced. Unfortunately, this solution does not prevent a consumer from reading even when there are no buffers to read. For example, if the first consumer reads before the first producer executes, then this solution will not work. Producer: while(1) { P(empty) P(mutex) obtain empty buffer and add next item, creating a full buffer V(mutex) ... } Consumer: while(1) { ... P(mutex) remove item from full buffer, create an empty buffer V(mutex) V(empty) }

22 Bounded Buffer Producer/Consumer Problem
So add a second counting semaphore full, initially set to 0 Verify for yourself that this solution won’t deadlock, synchronizes properly with mutual exclusion, prevents a producer from writing to a full buffer, and prevents a consumer from reading from an empty buffer Producer: while(1) { P(empty) P(mutex) obtain empty buffer and add next item, creating a full buffer V(mutex) V(full) } Consumer: while(1) { P(full) P(mutex) remove item from full buffer, create an empty buffer V(mutex) V(empty) }

23 The Readers/Writers Problem
There are several writer processes that want to write to a shared object, e.g. a file, and also several reader processes that want to read from the same shared object Want to synchronize access Shared object, e.g. file Writers Readers W1 R1 Readers can share with any other reader but not a writer a writer must have exclusive access W2 R2 The “First Readers/Writers Problem”: no reader is kept waiting unless a writer already has seized the shared object. We will implement this in the next slides.

24 The Readers/Writers Problem
readers share data structures: semaphore mutex, wrt; // initialized to 1 int readcount; // initialized to 0, controlled by mutex writers also share semaphore wrt Writer: while(1) { wait(wrt); // writing signal(wrt); } Reader: while(1) { wait(mutex); readcount++; if (readcount==1) wait(wrt); signal(mutex); // reading readcount--; if (readcount==0) signal(wrt); }

25 The Readers/Writers Problem
If multiple writers seek to write, then the write semaphore wrt provides mutual exclusion If the 1st reader tries to read while a writer is writing, then the 1st reader blocks on wrt if subsequent readers try to read while a writer is writing, they block on mutex If the 1st reader reads and there are no writers, then 1st reader grabs the write lock and continues reading, eventually releasing the write lock when done reading if a writer tries to write while the 1st reader is reading, then the writer blocks on the write lock wrt if a 2nd or any subsequent reader tries to read while the 1st reader is reading, then it falls through and is allowed to read

26

27 Synchronization // counter--; // counter++ reg2 = counter;
Suppose we have the following sequence of interleaving, where the brackets [value] denote the local value of counter in either the producer or consumer’s process. Let counter=5 initially. // counter--; reg2 = counter; reg2 = reg2 - 1; counter = reg2; // counter++ reg1 = counter; reg1 = reg1 + 1; counter = reg1; (1) [5] (2) [5] (3) [6] (4) [4] (5) [6] (6) [4] At the end, counter = 4. But if steps (5) and (6) were reversed, then counter=6 !!! Value of shared variable counter changes depending upon (an arbitrary) order of writes - very undesirable!

28 Critical Section Some kernel data structures could be subject to race conditions, e.g. access to list of open files Kernel developer must ensure that no such race conditions occur User or kernel developer identifies critical sections in code where each process accesses shared variables access to critical sections is controlled by special entry and exit code while(1) { entry section critical section (manipulate common var’s) exit section remainder code }

29 Critical Section Critical section access should satisfy multiple properties mutual exclusion if process Pi is executing in its critical section, then no other processes can be executing in their critical sections progress if no process is executing in its critical section and some processes wish to enter their critical sections, then only those processes that are not executing in their remainder sections can participate in the decision on which will enter its critical section next this selection cannot be postponed indefinitely bounded waiting there exists a bound, or limit, on the number of times other processes can enter their critical sections after a process X has made a request to enter its critical section and before that request is granted

30 Critical Section How do we protect access to critical sections?
want to prevent another process from executing while current process is modifying this variable - mutual exclusion disable interrupts before entering critical section, disable interrupts after exiting critical section, reenable interrupts This provides mutual exclusion

31 Disabling Interrupts Code for p1 Code for p2 shared int counter;
disableInterrupts(); disableInterrupts(); counter++; counter--; enableInterrupts(); enableInterrupts(); Unfortunately, this approach has many drawbacks: Interrupts could be disabled arbitrarily long, e.g. the program may have an intentional or mistaken infinite loop Interrupts can be disabled too long, e.g. if the critical section has many lines of code, then other process are blocked from executing until this process reenables interrupts Really only want to prevent p1 and p2 from interfering with one another; this blocks all pi overlapped I/O may be prevented

32 Critical Section Alternative: don’t disable interrupts for the entire time you’re in the critical section Alternative Solution: Set a variable/flag called a lock to indicate that the critical section is busy, then unset the flag when critical section is done doesn’t disable interrupts in the critical section a process P can now be interrupted in the critical section, but if it is, P still has the lock, so no other process will be able to acquire the lock and execute its critical code

33 First Try at Lock Implementation
shared boolean lock = FALSE; shared int counter; Code for p1 Code for p2 /* Acquire the lock */ /* Acquire the lock */ while(lock) ; while(lock) ; lock = TRUE; lock = TRUE; /* Execute critical sect */ /* Execute critical sect */ counter++; counter--; /* Release lock */ /* Release lock */ lock = FALSE; lock = FALSE; modified version of Pearson slides

34 First Try at Lock Implementation
shared boolean lock = FALSE; shared int counter; Code for p1 Code for p2 /* Acquire the lock */ /* Acquire the lock */ while(lock) ; while(lock) ; lock = TRUE; lock = TRUE; /* Execute critical sect */ /* Execute critical sect */ counter++; counter--; /* Release lock */ /* Release lock */ lock = FALSE; lock = FALSE; p1 p2 at while Blocked lock = TRUE lock = FALSE Interrupt If P1 is blocked on I/O and has the lock, then P2 blocks as expected (P2 busy waits) modified version of Pearson slides

35 First Try at Lock Implementation
shared boolean lock = FALSE; shared double balance; Code for p1 Code for p2 /* Acquire the lock */ /* Acquire the lock */ while(lock) ; while(lock) ; lock = TRUE; lock = TRUE; /* Execute critical sect */ /* Execute critical sect */ counter++; counter--; /* Release lock */ /* Release lock */ lock = FALSE; lock = FALSE; This approach to protecting critical code is unsafe, because it is subject to a race condition If P1 is has just completed the test “while(lock)” and is just before the setting of “lock=TRUE”, P1 can get context switched out Then P2 executes and sees lock=FALSE in its while(lock) test, and also drops through to the lock=TRUE statement Now both P1 and P2 are executing in critical section - BAD

36 Atomic Lock Manipulation
while (lock==TRUE) ; // test if lock taken lock = TRUE; // if not taken, set lock as taken test-and-set approach of the above two lines from the previous slide doesn’t work if process is interrupted right after while() instead, want the test-and-set process to be atomic, i.e. uninterruptable Want an atomic instruction TestandSet() that tests shared variable lock then sets it Some hardware provides such an instruction TS

37 Atomic Lock Manipulation
shared boolean lock = FALSE; shared int counter; Code for p1 Code for p2 /* Acquire the lock */ /* Acquire the lock */ while(TestandSet(&lock)) ; while(TestandSet(&lock)) ; /* Execute critical sect */ /* Execute critical sect */ counter++; counter--; /* Release lock */ /* Release lock */ lock = FALSE; lock = FALSE; ______________________________________________________________ boolean TestandSet(boolean *target) { // this is atomic, executed as one machine instruction boolean rv = *target; *target = TRUE; return rv; }

38 Atomic Lock Manipulation
Mutual exclusion is achieved - no race conditions If one process X tries to obtain the lock while another process Y already has it, X will wait in the loop If a process is testing and/or setting the lock, no other process can interrupt it The system is exclusively occupied for only a short time - the time to test and set the lock, and not for entire critical section only about 10 instructions don’t have to disable and reenable interrupts - time-consuming disadvantage: requires user to put in while() requires special hardware support in the form of a low level atomic machine instruction TS

39 Atomic Lock Manipulation
Here’s another implementation of locks that doesn’t require a special hardware instruction - uses just disabling and reenabling of interrupts Bounds the amount of time that interrupts are disabled to only lock manipulation, not the entire critical section Acquire(lock) { Release(lock) { disableInterrupts(); disableInterrupts(); /* Loop until lock is TRUE */ lock = FALSE; while(lock) { enableInterrupts(); /* Let interrupts occur */ } enableInterrupts(); disableInterrupts(); } lock = TRUE;

40 Semaphores more general solution to mutual exclusion
Semaphore S is an integer variable that, apart from initialization, is accessed only through 2 standard atomic operations P(), also called wait(), short for Dutch word proberen “to test” somewhat equivalent to a test-and-set, but also involves decrementing the value of S V(), also called signal(), short for Dutch word verhogen “to increment” increments the value of S OS provides ways to create and manipulate semaphores atomically

41 Semaphores Pseudo-code for classic semaphore P(S) { while(S<=0)
its value can’t go below zero, i.e. classic semaphore is non-negative P(S) { while(S<=0) {wait or no op;} S--; } V(S) { S++; } atomic atomic

42 Semaphores Here’s an intuitive implementation of semaphores using only disabling and reenabling of interrupts See the text for an example of implementing semaphores using TestandSet() instructions P(S) { disableInterrupts(); while(S==0) { enableInt(); disableInt(); } S--; enableInt() V(S) { disableInt(); S++; enableInt() }

43 Semaphores Usage example: Suppose the initial value of S is Sinit = 1
The first process X that calls P() on semaphore S will check if S<=0 (it is not), and then will decrement S to 0 this is performed atomically If a 2nd process Y calls P() for semaphore S, then Y will block on the semaphore, because now S=0, which satisfies the while test of S<=0 other processes that call P(S) will also block on the semaphore When process X is done, X will V() the semaphore S, incrementing S atomically to 1 Process Y will now check the semaphore and see that its value is now 1, so it can jump out of the while() loop and decrement S back to 0, thus completing its original P(S) Mutual exclusion is achieved

44 Semaphores Usage example: mutual exclusion
Semaphore S = 1; // initial value of semaphore is 1 int counter; // assume counter is set correctly somewhere in code Process P1: P(S); // execute critical section counter++; V(S); Process P2: P(S); // execute critical section counter--; V(S); Both processes atomically P() and V() the semaphore S, which protects access to critical section code, in this case access to the shared variable counter

45 Semaphores The previous example showed how to use the semaphore as a binary semaphore its initial value was set to 1 a binary semaphore is also called a mutex lock, i.e. it can be used to provide mutual exclusion on some piece of critical code A semaphore can also be used more generally as a counting semaphore its initial value is n, e.g. n=10 the value of the semaphore is used to store the value of a shared variable, or is used to keep track of the number of processes allowed to access some shared resource

46

47 Bounded Buffer Problem
Empty Pool Producer Consumer Full Pool

48 Bounded Buffer Problem (2)
producer() { buf_type *next, *here; while(TRUE) { produce_item(next); /* Claim an empty */ P(empty); P(mutex); here = obtain(empty); V(mutex); copy_buffer(next, here); release(here, fullPool); /* Signal a full buffer */ V(full); } semaphore mutex = 1; semaphore full = 0; /* A general (counting) semaphore */ semaphore empty = N; /* A general (counting) semaphore */ buf_type buffer[N]; fork(producer, 0); fork(consumer, 0); consumer() { buf_type *next, *here; while(TRUE) { /* Claim full buffer */ P(mutex); P(full); here = obtain(full); V(mutex); copy_buffer(here, next); release(here, emptyPool); /* Signal an empty buffer */ V(empty); consume_item(next); }

49 Bounded Buffer Problem (3)
producer() { buf_type *next, *here; while(TRUE) { produce_item(next); /* Claim an empty */ P(empty); P(mutex); here = obtain(empty); V(mutex); copy_buffer(next, here); release(here, fullPool); /* Signal a full buffer */ V(full); } semaphore mutex = 1; semaphore full = 0; /* A general (counting) semaphore */ semaphore empty = N; /* A general (counting) semaphore */ buf_type buffer[N]; fork(producer, 0); fork(consumer, 0); consumer() { buf_type *next, *here; while(TRUE) { /* Claim full buffer */ P(full); P(mutex); here = obtain(full); V(mutex); copy_buffer(here, next); release(here, emptyPool); /* Signal an empty buffer */ V(empty); consume_item(next); }

50 Readers-Writers Problem

51 Readers-Writers Problem (2)
Shared Resource

52 Readers-Writers Problem (3)
Shared Resource

53 Readers-Writers Problem (4)
Shared Resource

54 First Solution First reader competes with writers
while(TRUE) { <other computing>; P(mutex); readCount++; if(readCount == 1) P(writeBlock); V(mutex); /* Critical section */ access(resource); readCount--; if(readCount == 0) V(writeBlock); } resourceType *resource; int readCount = 0; semaphore mutex = 1; semaphore writeBlock = 1; fork(reader, 0); fork(writer, 0); writer() { while(TRUE) { <other computing>; P(writeBlock); /* Critical section */ access(resource); V(writeBlock); } First reader competes with writers Last reader signals writers

55 First Solution (2) First reader competes with writers
while(TRUE) { <other computing>; P(mutex); readCount++; if(readCount == 1) P(writeBlock); V(mutex); /* Critical section */ access(resource); readCount--; if(readCount == 0) V(writeBlock); } resourceType *resource; int readCount = 0; semaphore mutex = 1; semaphore writeBlock = 1; fork(reader, 0); fork(writer, 0); writer() { while(TRUE) { <other computing>; P(writeBlock); /* Critical section */ access(resource); V(writeBlock); } First reader competes with writers Last reader signals writers Any writer must wait for all readers Readers can starve writers “Updates” can be delayed forever May not be what we want

56 Writer Precedence 4 3 2 1 reader() { while(TRUE) {
<other computing>; P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); access(resource); readCount--; if(readCount == 0) V(writeBlock); } int readCount = 0, writeCount = 0; semaphore mutex = 1, mutex2 = 1; semaphore readBlock = 1, writeBlock = 1, writePending = 1; fork(reader, 0); fork(writer, 0); writer() { while(TRUE) { <other computing>; P(mutex2); writeCount++; if(writeCount == 1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); } 4 3 2 1

57 Writer Precedence (2) 4 3 2 1 reader() { while(TRUE) {
<other computing>; P(writePending); P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); V(writePending); access(resource); readCount--; if(readCount == 0) V(writeBlock); } int readCount = 0, writeCount = 0; semaphore mutex = 1, mutex2 = 1; semaphore readBlock = 1, writeBlock = 1, writePending = 1; fork(reader, 0); fork(writer, 0); writer() { while(TRUE) { <other computing>; P(mutex2); writeCount++; if(writeCount == 1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); } 4 3 2 1

58 The Sleepy Barber Barber can cut one person’s hair at a time
Other customers wait in a waiting room Entrance to Waiting Room (sliding door) Shop Exit Entrance to Barber’s Room (sliding door) Waiting Room

59 Sleepy Barber (aka Bounded Buffer)
customer() { while(TRUE) { customer = nextCustomer(); if(emptyChairs == 0) continue; P(chair); P(mutex); emptyChairs--; takeChair(customer); V(mutex); V(waitingCustomer); } semaphore mutex = 1, chair = N, waitingCustomer = 0; int emptyChairs = N; fork(customer, 0); fork(barber, 0); barber() { while(TRUE) { P(waitingCustomer); P(mutex); emptyChairs++; takeCustomer(); V(mutex); V(chair); }

60 Cigarette Smoker’s Problem
Three smokers (processes) Each wish to use tobacco, papers, & matches Only need the three resources periodically Must have all at once 3 processes sharing 3 resources Solvable, but difficult

61 Implementing Semaphores
Minimize effect on the I/O system Processes are only blocked on their own critical sections (not critical sections that they should not care about) If disabling interrupts, be sure to bound the time they are disabled

62 Implementing Semaphores: enter() & exit()
class semaphore { int value; public: semaphore(int v = 1) { value = v;}; P(){ disableInterrupts(); while(value == 0) { enableInterrupts(); } value--; }; V(){ value++;

63 Implementing Semaphores: Test and Set Instruction
TS(m): [Reg_i = memory[m]; memory[m] = TRUE;] Data Register CC Register TRUE m Primary Memory FALSE R3 =0 Data Register CC (b) After Executing TS R3 m FALSE Primary Memory Before Executing TS

64 Using the TS Instruction
boolean s = FALSE; . . . while(TS(s)) ; <critical section> s = FALSE; semaphore s = 1; . . . P(s) ; <critical section> V(s);

65 Implementing the General Semaphore
struct semaphore { int value = <initial value>; boolean mutex = FALSE; boolean hold = TRUE; }; shared struct semaphore s; P(struct semaphore s) { while(TS(s.mutex)) ; s.value--; if(s.value < 0) ( s.mutex = FALSE; while(TS(s.hold)) ; } else V(struct semaphore s) { while(TS(s.mutex)) ; s.value++; if(s.value <= 0) ( while(!s.hold) ; s.hold = FALSE; } s.mutex = FALSE;

66 Active vs Passive Semaphores
A process can dominate the semaphore Performs V operation, but continues to execute Performs another P operation before releasing the CPU Called a passive implementation of V Active implementation calls scheduler as part of the V operation. Changes semantics of semaphore! Cause people to rethink solutions

67 Atomic Lock Manipulation
shared double balance; shared int lock = FALSE; P1 enter(lock); counter++; exit(lock); P2 enter(lock); // atomic system call counter--; exit(lock);

68 Atomic Lock Manipulation
enter(lock) { exit(lock) { disableInterrupts(); disableInterrupts(); /* Loop until lock is TRUE */ lock = FALSE; while(lock) { enableInterrupts(); /* Let interrupts occur */ } enableInterrupts(); disableInterrupts(); } lock = TRUE; Bound the amount of time that interrupts are disabled Can include other code to check that it is OK to assign a lock … but this is still overkill …

69

70 Critical Section do { flag[i] = TRUE turn = j;
while (flag[j] && turn==j); critical section flag[i] = FALSE remainder section } while (TRUE)

71 Critical Section Solution: instead disable only on entry and exit. Use a shared variable to control access to another shared variable. this introduces complexity - what if you’re interrupted while having the lock?


Download ppt "More on Classic Synchronization Problems, Monitors, and Deadlock"

Similar presentations


Ads by Google