350 likes | 543 Views
Background. Shared-memory solution to bounded-buffer problem allows at most n – 1 items in buffer at the same time. A solution, where all N buffers are used is not simple.
E N D
Background • Shared-memory solution to bounded-buffer problem allows at most n – 1 items in buffer at the same time. • A solution, where all N buffers are used is not simple. • Suppose that we modify the producer-consumer code by adding a variable counter, initialized to 0 and incremented each time a new item is added to the buffer • Shared data #define BUFFER_SIZE 10 typedef struct { . . . } item; item buffer[BUFFER_SIZE]; int in = 0; int out = 0; int counter = 0; Operating System Concepts
Bounded-Buffer Attempt • Producer process while (1) { while (counter == BUFFER_SIZE) ; /* do nothing */ buffer[in] = nextProduced; in = (in + 1) % BUFFER_SIZE; counter++; } • Consumer process while (1) { while (counter == 0) ; /* do nothing */ nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; counter--; } Operating System Concepts
Bounded Buffer • The statement counter++ may be implemented in machine language as: register1 = counter register1 = register1 + 1counter = register1 • The statement counter-- may be implemented as:register2 = counterregister2 = register2 – 1counter = register2 • If both the producer and consumer attempt to update the counter concurrently, the assembly language statements may get interleaved. Operating System Concepts
Bounded Buffer • Assume counter is initially 5. One interleaving of statements is: producer: register1 = counter (register1 = 5)producer: register1 = register1 + 1 (register1 = 6)consumer: register2 = counter (register2 = 5)consumer: register2 = register2 – 1 (register2 = 4)producer: counter = register1 (counter = 6)consumer: counter = register2 (counter = 4) • The value of counter may be either 4 or 6, where the correct result should be 5. • Interleaving depends upon how the producer and consumer processes are scheduled. • The statements counter++; and counter--; must be performed atomically. • Atomic operation means an operation that completes in its entirety without interruption. Operating System Concepts
Race Condition • Concurrent access to shared data may result in data inconsistency. • Race condition: The situation where several processes access – and manipulate shared data concurrently. The final value of the shared data depends upon which process finishes last. • To prevent race conditions, concurrent processes must be synchronized. • The concurrent processes have critical sections, in which they modify shared data • A limited number of processes can be in their critical sections at the same time. Operating System Concepts
The Critical-Section Problem • N processes all competing to use some shared data • Each process has a code segment, called critical section, in which the shared data is accessed. • Problem – ensure that maximally R (often R = 1) processes executing in their critical section. • General structure of process Pi do { entry section critical section exit section remainder section } while (1); Operating System Concepts
Solution to Critical Section Problem • Requirements • Mutual Exclusion - Maximally R processes in their critical section • Progress - If less than R processes are in their critical sections, then a process that wishes to enter it critical section is not delayed indefinitely. • Bounded Waiting - Only a bounded amount of “overtaking” into critical sections is permitted. • Assumptions • Assume that each process executes at a non-zero speed • No assumption concerning relative speed of the processes. • Atomic execution of machine code instructions (think of the fetch-interrupt?-decode-execute cycle) • Types of solutions • Software - no hardware support but slow • Hardware supported Operating System Concepts
2 Processes, 1 at-a-time, Algorithm 1 • Processes P0 and P1 • Shared variables: • int turn = 0; • turn = i Pi can enter its critical section • Process Pi do { while (turn != i) ; critical section turn = 1 - i; reminder section } while (1); • Satisfies mutual exclusion, but not progress • A process can be stuck in its remainder • Problem is forced alternation Operating System Concepts
2 Processes, 1 at-a-time, Algorithm 2 • Shared variables • boolean flag[2] = {false,false}; • flag[i] = true Pi ready to enter its critical section • Process Pi do { flag[i] := true; while (flag[1-i]) ; critical section flag[i] = false; remainder section } while (1); • Satisfies mutual exclusion, but not progress • Both can set flag[i] before proceeding • Switching the first two lines violates mutual exclusion Operating System Concepts
2 Processes, 1 at-a-time, Algorithm 3(Peterson’s Algorithm) • Combined shared variables of algorithms 1 and 2. • Process Pi do { flag[i]:= true; //----I’m ready turn = 1-i; //----It’s your turn (last RAM access) while (flag[1-i] and turn == 1-i) ; //----Wait if other is ready and it’s its turn critical section flag[i] = false; //----I’m not ready any more remainder section } while (1); • Meets all three requirements; solves the critical-section problem for two processes. Operating System Concepts
N Processes, 1 at-a-time, Bakery Algorithm • Before entering its critical section, process receives a number. Holder of the smallest number enters the critical section. • If processes Pi and Pj receive the same number, if i < j, then Pi is served first; else Pj is served first. • Numbers are handed out in non-decreasing order, e.g., 1,2,3,3,3,3,4,5... • Notation < lexicographical order (ticket #, process id #) • (a,b) < (c,d) if a < c or if a = c and b < d Operating System Concepts
Bakery Algorithm • Shared data boolean choosing[n] = {false*}; int number[n] = {0*}; • Algorithm for Pi do { choosing[i] = true; number[i] = max(number[0],number[1],…,number[n–1])+1; choosing[i] = false; for (j=0; j<n; j++) { while (choosing[j]) ; //---Wait for a process that is getting a number while (number[j] != 0 && (number[j],j) < (number[i],i)) ; //---Wait for process with better numbers } critical section number[i] = 0; //---Release the number and interest remainder section } while (1); Operating System Concepts
Hardware Supported Solutions • Turn off interrupts • Affects multi-tasking - too dangerous • Affects clock • Affects critical OS activities • Atomically swap two variables. void Swap(boolean &a, boolean &b) { boolean temp = a; a = b; b = temp; } • Test and modify the content of a word atomically boolean TestAndSet(boolean &target) { boolean return_value = target; target = true; return(return_value); } Operating System Concepts
N Processes, 1 at-a-time, Using swap • Shared data boolean lock = false; //----Nobody using • Local data boolean key; • Process Pi do { key = true; //---I want in while (key) //---Wait until free Swap(lock,key); critical section lock = false; //---Set it free remainder section } • Does not satisfy bounded wait Operating System Concepts
N Processes, 1 at-a-time, Using T&S • Shared data: boolean lock = false; • Process Pi do { while (TestAndSet(lock)) ; critical section lock = false; remainder section } • Does not satisfy bounded wait Operating System Concepts
N Processes, 1 at-a-time, Using T&S • Shared data boolean waiting[0..n-1] = {false*}; boolean lock = false; • Algorithm for Pi while (1) { waiting[i] = true; //---I want in key = true; //---Assume another is in C.S. while (waiting[i] && key) key = TestAndSet(lock); //---Busy wait waiting[i] = false critical section j = (i+1) % n; //---Look to see who’s waiting while (j != i && !waiting[j]) j = (j+1) % n; if (j == i) then lock = false; //----No one else waiting[j] = false; //---Someone remainder section } (see Geoff’s example) Operating System Concepts
Semaphores • Working towards a synchronization tool that does not require busy waiting. • Semaphore S – integer variable • Can only be accessed via two atomic operations wait(S): //---P(S) when S > 0 do S--; signal(S): //----V(S) S++; Operating System Concepts
N Processes, R at-a-time, Using Semaphores • Shared data: semaphore mutex = R; //----R processes in parallel • Process Pi: do { wait(mutex); critical section signal(mutex); remainder section } while (1); Operating System Concepts
Semaphore as a General Synchronization Tool • Execute B in Pj only after A executed in Pi • Use semaphore flag initialized to 0 • Code: Pi Pj Await(flag) signal(flag) B Operating System Concepts
Implementing Semaphores • How to implement wait? wait(S): while (S <= 0) //---Busy wait ; S--; //---Not atomic? • How to implement signal? signal(S): S++; //---Not atomic? Operating System Concepts
Spinlock Binary Semaphore Implementation • Spinlock binary semaphores implemented with T&S • B = FALSE means B = 1 • B = TRUE means B = 0 wait(B): while (TestAndSet(B)) ; signal(B): B = false; • Note the busy wait in wait(B) • Will be avoided in general semaphore implementation • When used for CS problem, bounded-wait is violated because while is not indivisible • However, useful in some situations Operating System Concepts
Spinlock Semaphore Implementation • Data structures: binary-semaphore B1=1, B2=0; int C = R; • When C is less than 0 the semaphore value is 0. • wait operation wait(B1); //---Mutex on C C--; if (C < 0) { //---Have to stop here signal(B1); wait(B2); //---Busy wait } signal(B1); • signal operation wait(B1); C++; if (C <= 0) signal(B2); else signal(B1); Operating System Concepts
Semaphore Implementation • Assume two simple operations: • block(P) moves P to the waiting state, with the PCB linked into the semaphore list • wakeup(P) moves P to the ready state Operating System Concepts
Semaphore Implementation wait(P,S): wait(B1) //---Short busy wait C-- if (C < 0) block(P); signal(B1) signal(P,S): wait(B1) //---Short busy wait C++ if (C <= 0) wakeup(Someone) //---“when” and S-- signal(B1) • When C is less than 0 the semaphore value is 0. Operating System Concepts
Semaphore Implementation Expanded wait(P,S): while (TestAndSet(B1)) ; C-- if (C < 0) block(P); B1 = FALSE signal(P,S): while (TestAndSet(B1)) ; C++ if (C <= 0) wakeup(Someone) B1 = FALSE Operating System Concepts
Bounded-Buffer Problem • Shared datasemaphore full = 0, empty = R, mutex = 1; • Producer Process do { produce an item in nextp wait(empty); wait(mutex); add nextp to buffer signal(mutex); signal(full); } while (1); • Consumer Process do { wait(full) wait(mutex); remove an item from buffer to nextc signal(mutex); signal(empty); consume the item in nextc } while (1); Operating System Concepts
Readers-Writers Problem 1 • Shared datasemaphore mutex = 1, wrt = 1;int readcount = 0; //---Number of readers in action • Writer Process wait(wrt); writing is performed signal(wrt); • Reader Process wait(mutex); //---Mutex on readcount readcount++; if (readcount == 1) //---First reader wait(wrt); //---Wait to lock out writers signal(mutex); reading is performed wait(mutex); readcount--; if (readcount == 0) //---Last reader signal(wrt); //---Allow writers signal(mutex): Operating System Concepts
Dining-Philosophers Problem • Shared data semaphore chopstick[N] = {1*}; • Philosopher i: do { wait(chopstick[i]); wait(chopstick[(i+1) % N]); eat; signal(chopstick[i]); signal(chopstick[(i+1) % N]); think; } while (1); • Leads to deadlock • Limit philosophers • Pickup both at once • Asymmetric pickup Operating System Concepts
Critical Regions • High-level synchronization construct • A shared variable v of type T, is declared as: v: shared T • Variable v accessed only inside statement region v when B do S; where B is a boolean expression. • Only one process can be in a region at a time. • When a process executes the region statement, B is evaluated. • If B is true, statement S is executed. • If B is false, the process is queued until no process is in the region associated with v, and B is tested again Operating System Concepts
Example – Bounded Buffer • Shared data: buffer : shared struct { int pool[n]; int count, in, out; } • Producer region buffer when (count < n) do { pool[in] = nextp; in:= (in+1) % n; count++; } • Consumer region buffer when (count > 0) do { nextc = pool[out]; out = (out+1) % n; count--; } Operating System Concepts
Monitors • High-level synchronization construct that allows the safe sharing of an abstract data type among concurrent processes. monitor monitor-name { shared variable declarations procedure body P1 (…) { . . . //---Can access shared vars and params } procedure body P2 (…) { . . . } procedure body Pn (…) { . . . } { initialization code } } • Only one process can be executing in a monitor at a time Operating System Concepts
Schematic View of a Monitor Operating System Concepts
Monitors • To allow a process to wait within the monitor, a condition variable must be declared, as condition x, y; • Condition variable can only be used with the operations wait and signal. • The operation x.wait();means that the process invoking this operation is suspended until another process invokes x.signal(); • The x.signal operation resumes exactly one suspended process. If no process is suspended, then the signal operation has no effect. • Hmmm, which runs, signaller or signalled? Compromise - signaller must exit the monitor Operating System Concepts
Monitor With Condition Variables Operating System Concepts
Dining Philosophers Example monitor dp { enum {thinking, hungry, eating} state[5]; condition self[5]; void pickup(int i) { state[i] = hungry; test[i]; if (state[i] != eating) self[i].wait(); } void putdown(int i) { state[i] = thinking; test((i+4) % 5); test((i+1) % 5); } void test(int i) { if ( (state[(i+4) % 5] != eating) && (state[i] == hungry) && (state[(i+1) % 5] != eating)) { state[i] = eating; self[i].signal(); } } void init() { for (int i = 0; i < 5; i++) state[i] = thinking; } } Operating System Concepts