Presentation is loading. Please wait.

Presentation is loading. Please wait.

Synchronization CSCI 3753 Operating Systems Spring 2005 Prof. Rick Han.

Similar presentations


Presentation on theme: "Synchronization CSCI 3753 Operating Systems Spring 2005 Prof. Rick Han."— Presentation transcript:

1

2 Synchronization CSCI 3753 Operating Systems Spring 2005 Prof. Rick Han

3 Announcements HW #3 is online, due Friday Feb. 25 at 11 am PA #2 is coming, assigned next Tuesday Midterm is tentatively Thursday March 10 Read chapter 8

4 From last time... Many cases where processes and threads want to access shared common variables, buffers, etc. Producer-Consumer with a shared bounded buffer in between –Producer increments counter++ –Consumer decrements counter-- race conditions between producer and consumer –Machine-level instructions can be interleaved, resulting in unpredictable value of shared counter variable

5 Synchronization while(1) { while(counter==MAX); buffer[in] = nextdata; in = (in+1) % MAX; counter++; } Data Bounded Buffer counter Producer Process Consumer Process while(1) { while(counter==0); getdata = buffer[out]; out = (out+1) % MAX; counter--; } Producer writes new data into buffer and increments counter Consumer reads new data from buffer and decrements counter counter updates can conflict! buffer[0] buffer[MAX]

6 Synchronization counter++; can translate into several machine language instructions, e.g. reg1 = counter; reg1 = reg1 + 1; counter = reg1; counter--; can translate into several machine language instructions, e.g. reg2 = counter; reg2 = reg2 - 1; counter = reg2; If these low-level instructions are interleaved, e.g. the Producer process is context-switched out, and the Consumer process is context-switched in, and vice versa, then the results of counter’s value can be unpredictable

7 Synchronization // counter++ reg1 = counter; reg1 = reg1 + 1; counter = reg1; // counter--; reg2 = counter; reg2 = reg2 - 1; counter = reg2; ( 1) [5] ( 3) [6] ( 2) [5] ( 4) [4] ( 5) [6] ( 6) [4] 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. 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!

8 Critical Section Kernel data structures - e.g. access to list of open files subject to race condition Kernel developer must ensure that no such race conditions occur Identify critical sections in code where each process access shared variables do { entry section critical section (manipulate common var’s) exit section remainder code } while (1) mutual exclusion, bounded waiting, progress

9 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 bad, because I/O may be prevented bad, because program may have an infinite loop

10 Critical Section Don’t disable interrupts for the entire time you’re in the critical section 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 –also Peterson’s solution

11 Using a Lock Variable shared boolean lock = FALSE; shared int counter; Code for p 1 Code for p 2/* Acquire the lock */ while(lock) ; lock = TRUE;/* Execute critical sect */ counter++; counter--;/* Release lock */ lock = FALSE;

12 Busy Wait Condition shared boolean lock = FALSE; shared int counter; Code for p 1 Code for p 2/* Acquire the lock */ while(lock) ; lock = TRUE;/* Execute critical sect */ counter++; counter--;/* Release lock */ lock = FALSE; p1p1 p2p2 Blocked at while lock = TRUE lock = FALSE Interrupt

13 Unsafe “Solution” shared boolean lock = FALSE; shared double balance; Code for p 1 Code for p 2/* Acquire the lock */ while(lock) ; lock = TRUE;/* Execute critical sect */ counter++; counter--;/* Release lock */ lock = FALSE; Worse yet … another race condition … Is it possible to solve the problem?

14 Critical Section while (lock==TRUE) ; lock = TRUE; test-and-set solution doesn’t work if process is interrupted right after while() Want an atomic instruction testandset() that tests shared variable lock then sets it Some hardware provides such an instruction

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

16 Atomic Lock Manipulation The system is exclusively occupied for only a short time - the time to test and set the lock, and not for entire critical section –about 10 instructions don’t have to disable and reenable interrupts - time-consuming disadvantage: requires user to put in while() low level assembly language manipulation of a machine instruction TS

17

18 Bounded Buffer Problem Producer Consumer Empty Pool Full Pool

19 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); P(mutex); release(here, fullPool); V(mutex); /* 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); P(mutex); release(here, emptyPool); V(mutex); /* Signal an empty buffer */ V(empty); consume_item(next); }

20 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); P(mutex); release(here, fullPool); V(mutex); /* 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); P(mutex); release(here, emptyPool); V(mutex); /* Signal an empty buffer */ V(empty); consume_item(next); }

21 Readers-Writers Problem Readers Writers

22 Readers-Writers Problem (2) Reader Shared Resource Reader Writer

23 Readers-Writers Problem (3) Reader Shared Resource Reader Writer

24 Readers-Writers Problem (4) Reader Shared Resource Reader Writer

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

26 First Solution (2) reader() { while(TRUE) { ; P(mutex); readCount++; if(readCount == 1) P(writeBlock); V(mutex); /* Critical section */ access(resource); P(mutex); readCount--; if(readCount == 0) V(writeBlock); V(mutex); } resourceType *resource; int readCount = 0; semaphore mutex = 1; semaphore writeBlock = 1; fork(reader, 0); fork(writer, 0); writer() { while(TRUE) { ; 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

27 Writer Precedence reader() { while(TRUE) { ; P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); access(resource); P(mutex1); readCount--; if(readCount == 0) V(writeBlock); V(mutex1); } 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) { ; P(mutex2); writeCount++; if(writeCount == 1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); V(mutex2); } 1234

28 Writer Precedence (2) reader() { while(TRUE) { ; P(writePending); P(readBlock); P(mutex1); readCount++; if(readCount == 1) P(writeBlock); V(mutex1); V(readBlock); V(writePending); access(resource); P(mutex1); readCount--; if(readCount == 0) V(writeBlock); V(mutex1); } 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) { ; P(mutex2); writeCount++; if(writeCount == 1) P(readBlock); V(mutex2); P(writeBlock); access(resource); V(writeBlock); P(mutex2) writeCount--; if(writeCount == 0) V(readBlock); V(mutex2); } 1234

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

30 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); }

31 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

32 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

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

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

35 Using the TS Instruction boolean s = FALSE;... while(TS(s)) ; s = FALSE;... semaphore s = 1;... P(s) ; V(s);...

36 Implementing the General Semaphore struct semaphore { int 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 s.mutex = FALSE; } V(struct semaphore s) { while(TS(s.mutex)) ; s.value++; if(s.value <= 0) ( while(!s.hold) ; s.hold = FALSE; } s.mutex = FALSE; }

37 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

38 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);

39 Atomic Lock Manipulation enter(lock) {exit(lock) { disableInterrupts(); /* Loop until lock is TRUE */ lock = FALSE; while(lock) { enableInterrupts(); /* Let interrupts occur */} enableInterrupts(); disableInterrupts(); } lock = TRUE; enableInterrupts(); } 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 …

40

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

42 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 "Synchronization CSCI 3753 Operating Systems Spring 2005 Prof. Rick Han."

Similar presentations


Ads by Google