Process Synchronization Operating System Concepts • • • • • • • • Module 4: PROCESS SYNCHRONIZATION Andrzej Bednarski, Ph.D. student Department of Computer and Information Science Linköping University, Sweden E-mail: andbe@ida.liu.se Background The Critical-Section Problem Synchronization Hardware Semaphores Classical Problems of Synchronization Critical Regions Monitors Atomic Transactions URL: http://www.ida.liu.se/~andbe The lecture notes are mainly based on Silberschatz’s, Galvin’s and Gagne’s book (“Operating System Concepts”, 6th ed., Addison-Wesley, 2002). No part of the lecture notes may be reproduced in any form, due to the copyrights reserved by Addison-Wesley. These lecture notes should only be used for internal teaching purposes at the Linköping University. 4.1 TDDB63 – Operating System Concepts – Background • Concurrent access to shared data may result in data inconsistency. • Maintaining data consistency requires mechanisms to ensure the orderly execution of cooperating processes. • Shared-memory solution to bounded-buffer problem (Chapter 4) 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 • Race Condition: outcome of execution depends on a particular order A. Bednarski • 4.3 Bounded-Buffer (Cont.) • • 4.2 Additional shared variable: + int counter = 0; Producer process: while (1) { /* produce an item in nextProduced */ while (counter == BUFFER_SIZE) ; /* do nothing */ buffer[in] = nextProduced; in = (in + 1) % BUFFER_SIZE; counter++; } TDDB63 – Operating System Concepts – • • 4.4 • • 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 when one process is executing in its critical section, no other process is allowed to execute in its critical section (protocol). Structure of process Pi do { entry section critical section exit section reminder section } while (1); The statements: + counter = counter + 1; + counter = counter - 1; must be executed atomically. A. Bednarski A. Bednarski The Critical Section Problem Consumer process: while (1) { while (counter == 0) ; /* do nothing */ nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; counter--; } TDDB63 – Operating System Concepts – A. Bednarski Bounded-Buffer • TDDB63 – Operating System Concepts – TDDB63 – Operating System Concepts – 4.5 TDDB63 – Operating System Concepts – A. Bednarski 4.6 1 Initial Attempts to Solve Problem Solution to Critical-Section Problem 1. Mutual Exclusion. If process Pi is executing in its critical section, then no other processes can be executing in their critical sections. • • Only 2 processes, P0 and P1 General structure of process Pi (other process Pj) do { entry section critical section exit section reminder section } while (1); 2. Progress. If no process is executing in its critical section and there exist some processes that wish to enter their critical section, then the selection of the processes that will enter the critical section next cannot be postponed indefinitely. 3. Bounded Waiting. A bound must exist on the number of times that other processes are allowed to enter their critical sections after a process has made a request to enter its critical section and before that request is granted. O Assume that each process executes at a nonzero speed O No assumption concerning relative speed of the n processes. TDDB63 – Operating System Concepts – A. Bednarski 4.7 Algorithm 1 • • • • • Satisfies mutual exclusion, but not progress + If turn==0 and P1 ready to enter critical section, P1 cannot do so even though P0 is in its remainder section + Not sufficient information about the state of each process A. Bednarski • 4.9 4.8 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[j]); critical section flag[i] = false; remainder section } while (1); Satisfies mutual exclusion, but not progress requirement. + P0 sets flag[0]=true; P1 sets flag[1]=true => infinite loop TDDB63 – Operating System Concepts – A. Bednarski 4.10 Bakery Algorithm Combined shared variables of algorithms 1 and 2. Process Pi do { flag[i] = true; turn = j; while (flag[j] && turn == j ); critical section flag[i] = false; remainder section } while (1); Meets all three requirements; solves the critical-section problem for two processes. TDDB63 – Operating System Concepts – A. Bednarski Algorithm 2 Algorithm 3 • Processes may share some common variables to synchronize their actions. TDDB63 – Operating System Concepts – Shared variables: int turn = 0; + turn == i Pi can enter its critical section Process Pi do { while (turn != i); critical section turn = j remainder section } while(1); TDDB63 – Operating System Concepts – • • • A. Bednarski Critical section for n processes 4.11 • 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. • The numbering scheme always generates numbers in increasing order of enumeration; i.e., 1,2,3,3,3,3,4,5... TDDB63 – Operating System Concepts – A. Bednarski 4.12 2 Bakery Algorithm (Cont.) Structure of Pi Bakery Algorithm (Cont.) • Notation <{ { lexicographical order (ticket #, process id #) + (a,b) < (c,d) if a < c or if a = c and b < d + max (a0,…, an-1) is a number, k, such that k t ai for i = 0, …, n – 1 • Shared data: boolean choosing[n]; int number[n]; 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]); /* busy waiting */ while ( (number[j] != 0) && (number[j],j) < (number[i], i) ); } critical section number[i] = 0; remainder section } while (1); Data structures are initialized to false and 0 respectively TDDB63 – Operating System Concepts – A. Bednarski 4.13 TDDB63 – Operating System Concepts – 4.14 A. Bednarski Synchronization Hardware Mutual Exclusion with TestAndSet • • Shared data: boolean lock = false ; • Process Pi do { while (TestAndSet(lock)); /* busy wait */ • • Idea: avoid/disable interrupts while common variables are changed Not applicable in multi-processor environments Test and modify the content of a word atomically: uninterruptable unit. boolean TestAndSet(boolean &target) { boolean rv = target; target = true ; return rv; } If multiple TestAndSet instructions are executed simultaneously (each on a different CPU), then they are executed sequentially in some arbitrary order. TDDB63 – Operating System Concepts – A. Bednarski 4.15 TestAndSet: Pros and Cons - Busy waiting is employed (spinning) - Starvation is possible: when a process leaves a critical section and more than one process is waiting, the selection of a waiting process is arbitrary; thus, some process could indefinitely be denied access. - Deadlock is possible: (i) P1 executes and enters its critical section (ii) P2 interrupts P1 due to high pri., but cannot enter its critical section (iii) P1 never dispatches again, since it’s low priority job A. Bednarski lock = false; /* release lock */ remainder section } while (1); TDDB63 – Operating System Concepts – 4.16 A. Bednarski Semaphores + Applicable to any number of processes on either uni- or multiprocessor machine + Simple and therefore easy to verify + Can support multiple critical sections (each critical section can be defined by its own variable) TDDB63 – Operating System Concepts – critical section 4.17 • • • • Synchronization tool that does not require busy waiting. Synchronization operations are atomic, i.e. indivisible + Operation P = wait (Dutch for proberen (test)) + Operation V = signal (Dutch for verhogen (increment)) Applicability: + N-process critical section problems + Synchronization problems, e.g., precedence constraints Semaphore S – integer variable wait (S ) { while (S <= 0) ; /* no-op */ S – –; } TDDB63 – Operating System Concepts – A. Bednarski signal (S ) { S ++; } 4.18 3 Example: Critical Section of n Processes Pros and Cons • Shared variable: semaphore mutex = 1; • Cons: + “Spin-lock” method -> requires busy waiting • Process Pi • Pros: + Spin-lock has no context switching when waiting; + Applicable in Multi-processor environments • Solution to busy-waiting: block yourself! do { wait(mutex); critical section signal(mutex); reminder section } while (1); TDDB63 – Operating System Concepts – A. Bednarski 4.19 Semaphore Implementation • Define a semaphore as a struct typedef struct { int value; struct process *L; } semaphore; • Assume two simple operations: + block suspends the process that invokes it. + wakeup(P ) resumes the execution of a blocked process P. TDDB63 – Operating System Concepts – A. Bednarski Execute B in Pj only after A executed in Pi • Use semaphore flag initialized to 0 • Code: Pi A signal(flag) TDDB63 – Operating System Concepts – • 4.21 4.20 Semaphore operations now defined as: void wait(semaphore S) { S.value--; if (S.value < 0) { add this process to S.L; block(); } } void signal(semaphore S) { S.value++; if (S.value <= 0) { remove a process P from S.L; wakeup(P ); } } TDDB63 – Operating System Concepts – A. Bednarski 4.22 Deadlock and Starvation • Deadlock – two or more processes are waiting indefinitely for an event that can be caused by only one of the waiting processes. • Let S and Q be two semaphores initialized to 1 P0 P1 wait(S ); wait(Q ); wait(Q ); wait(S ); signal(S ); signal(Q ); signal(Q ) signal(S); • Starvation – indefinite blocking. A process may never be removed from the semaphore queue in which it is suspended. (e.g., LIFO order) Pj wait(flag) B A. Bednarski A. Bednarski Implementation (Cont.) Semaphore as a General Synchronization Tool • TDDB63 – Operating System Concepts – 4.23 TDDB63 – Operating System Concepts – A. Bednarski 4.24 4 Implementing S using Binary Semaphore Two Types of Semaphores • • Counting semaphore – integer value can range over an unrestricted domain. • Binary semaphore – integer value can range only between 0 and 1; can be simpler to implement. + Can implement a counting semaphore S with a binary semaphore. • TDDB63 – Operating System Concepts – A. Bednarski binary-semaphore S1, S2; int C; • wait operation signal operation TDDB63 – Operating System Concepts – Initialization: S1 = 1; S2 = 0; C = initial value of semaphore S 4.25 Implementing S (Cont.) • Data structures: TDDB63 – Operating System Concepts – A. Bednarski Classical Problems of Synchronization wait(S1); C--; if (C < 0) { signal (S1); wait (S2); } signal (S1); • Bounded-Buffer Problem • Readers and Writers Problem • Dining-Philosophers Problem wait (S1); C++; if (C <= 0) signal (S2); else signal (S1); A. Bednarski 4.27 TDDB63 – Operating System Concepts – A. Bednarski Bounded-Buffer Problem Bounded-Buffer Problem (Cont.) • Producer process Consumer process do { … produce an item in nextp wait (empty); wait (mutex); … add nextp to buffer … signal (mutex); signal (full); } while(1); do { wait (full) wait (mutex); … remove an item from buffer to nextc … signal (mutex); signal (empty); … consume the item in nextc … } while (1); Shared data typedef struct { … } item; item buffer[BUFFER_SIZE]; semaphore full = n, empty = 0, mutex = 1; … TDDB63 – Operating System Concepts – 4.26 A. Bednarski 4.29 TDDB63 – Operating System Concepts – A. Bednarski 4.28 4.30 5 Readers-Writers Problem • Readers-Writers Problem (Cont.) • Shared data semaphore mutex = 1, wrt = 1; int readcount = 0; • Writer process wait (wrt); … writing is performed … signal (wrt); TDDB63 – Operating System Concepts – A. Bednarski 4.32 Dining-Philosophers Problem TDDB63 – Operating System Concepts – A. Bednarski Philosopher i : - Guarantees that neighbors are not eating simultaneously! - Does not guarantee avoidance of deadlocks! 4.34 TDDB63 – Operating System Concepts – A. Bednarski Dining-Philosophers Problem Three Deadlock-Free Solutions Programming problems using semaphores • Allow at most four philosophers to be sitting simultaneously at the table • Allow a philosopher to pick up her/his chopsticks only if both chopsticks are available (both in the same critical section) signal(mutex) critical section wait(mutex) Results in what? wait(mutex) critical section wait(mutex) Results in what? • 4.33 do { wait(chopstick[i ]); wait(chopstick[(i+1) % 5]); … eat … signal(chopstick[i]); signal(chopstick[(i+1) % 5]); … think … } while (1); Shared data semaphore chopstick[5] = {1, 1, 1, 1, 1}; TDDB63 – Operating System Concepts – A. Bednarski Dining-Philosophers Problem (Cont.) • • Reader process wait(mutex); readcount++; if (readcount == 1) wait(wrt); signal(mutex); … reading is performed … wait(mutex); readcount --; if (readcount == 0) signal(wrt); signal(mutex): Odd philosophers pick up left chopstick first; even philosophers pick up right chopstick first (Asymmetric solution) 4.35 Ommittance of signal or wait, what happens? TDDB63 – Operating System Concepts – A. Bednarski 4.36 TDDB63 – Operating System Concepts – A. Bednarski 4.37 6 Critical Regions Critical Regions (Cont.) • High-level synchronization construct + Can use, e.g., semaphores at low level. • Regions referring to the same shared variable exclude each other in time. • A shared variable v of type T, is declared as: v: shared T; • • Variable v accessed only inside region statements region v when B do S; When a process tries to execute the region statement, the boolean expression B is evaluated. If B is true, statement S is executed. If it is false, the process is delayed until B becomes true and no other process is in the region associated with v. • Pros: + Protects against certain simple errors associated with semaphore solution, that may be made by the programmer. where B is a boolean expression. While statement S is being executed, no other process can access variable v. TDDB63 – Operating System Concepts – A. Bednarski 4.38 TDDB63 – Operating System Concepts – A. Bednarski Example – Bounded Buffer Bounded Buffer Example (Cont.) • • • Shared variables: struct buffer { item pool[n]; int count, in, out; }; Producer process inserts nextp into the shared buffer region buffer when (count < n) { pool[in] = nextp; in = in+1 % n; count++; } TDDB63 – Operating System Concepts – A. Bednarski Consumer process removes an item from the shared buffer and puts it in nextc. region buffer when (count > 0) { nextc =pool[out]; out = (out+1) % n; count--; } 4.40 TDDB63 – Operating System Concepts – A. Bednarski Monitors Monitors cont. • • 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 (Note, in comparison, when using traditional semaphores, the value of the semaphore is changed) 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 (…) { …} procedure body P2 (…) { …} procedure body Pn (…) { …} { initialization code } } TDDB63 – Operating System Concepts – A. Bednarski 4.39 4.45 TDDB63 – Operating System Concepts – A. Bednarski 4.41 4.46 7 Schematic Overview of a Monitor TDDB63 – Operating System Concepts – A. Bednarski Monitor with condition variables 4.47 Dining Philosophers Example TDDB63 – Operating System Concepts – … 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 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); } A. Bednarski void init() { for (int i = 0; i < 5; i++) state[i] = thinking; } } 4.49 TDDB63 – Operating System Concepts – A. Bednarski Atomic Transactions Concurrent Atomic Transactions • Transactions - several operations grouped as one logical atomic/indivisible step of execution + Commit or abort (roll back) • • • • • Database technique Could provide more flexible and powerful techniques at OS level ”Transaction Processing Systems” • • Log-based Recovery Checkpoints + Log-recovery is performed since the last checkpoint (i.e., not the entire log) TDDB63 – Operating System Concepts – A. Bednarski 4.48 Dining Philosophers cont. monitor dp { enum { thinking, hungry, eating } state[5]; condition self[5]; TDDB63 – Operating System Concepts – A. Bednarski 4.56 4.50 Serializability Locking protocol - ensures serializability + 2PL - Two phase locking Growing phase: a transaction only obtains locks Shrinking phase: a transaction only releases locks TDDB63 – Operating System Concepts – A. Bednarski 4.57 8 Summary Recommended Reading and Exercises • • • • • Reading: + All but take 7.8 light • Exercises: + 1-16, 18-20, (21) Cooperation processes Mutual exclusion (critical section) Semaphores / Condition / Critical region / Monitor Transaction TDDB63 – Operating System Concepts – A. Bednarski 4.58 TDDB63 – Operating System Concepts – A. Bednarski 4.59 9