Engineered for Tomorrow Subject Name Operating Systems Subject
Engineered for Tomorrow Subject Name: Operating Systems Subject Code: 10 CS 53 Prepared By: Mrs. Jisha Jose, Mrs. Thanu Kurian, Mrs. Preethi Sheba Hepsiba Department: Computer Science Date: 30/08/2014 2/15/2022
Engineered for Tomorrow Unit-III Process Synchronization • • Background The Critical Section Problem Peterson’s Solution Synchronization hardware Semaphores Classical problems of synchronization Monitors 2/15/2022
Engineered for Tomorrow Background • Concurrent access to shared data may result in data inconsistency • Maintaining data consistency requires mechanisms to ensure the orderly execution of cooperating processes • Suppose the maximum size of Buffer is BUFFER_SIZE-1. • Solution – use an integer variable counter that keeps track of the number of items in the buffers. • Initially, counter is set to 0. • It is incremented every time, an item is added to the buffer & decremented, when an item is removed from the buffer. 2/15/2022
Engineered for Tomorrow Producer while (true) { /* produce an item and put in next. Produced */ while (counter == BUFFER_SIZE) ; // do nothing buffer [in] = next. Produced; in = (in + 1) % BUFFER_SIZE; counter++; } 2/15/2022
Engineered for Tomorrow Consumer while (true) { while (counter == 0) ; // do nothing next. Consumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; counter--; /* consume the item in next. Consumed */ } 2/15/2022
Engineered for Tomorrow • counter++ could be implemented as register 1 = counter register 1 = register 1 + 1 counter = register 1 • counter-- could be implemented as register 2 = counter register 2 = register 2 - 1 count = register 2 • Consider this execution interleaving with “count = 5” initially: S 0: producer execute register 1 = counter {register 1 = 5} S 1: producer execute register 1 = register 1 + 1 {register 1 = 6} S 2: consumer execute register 2 = counter {register 2 = 5} S 3: consumer execute register 2 = register 2 - 1 {register 2 = 4} S 4: producer execute counter = register 1 {count = 6 } S 5: consumer execute counter = register 2 {count = 4} 2/15/2022
Engineered for Tomorrow Contd. . Need for process synchronization • Several processes access & manipulate the same data concurrently. • Outcome of the execution depends on the particular order in which the access takes place. • This is called race condition. • To prevent this, only 1 process at a time, should manipulate the data. • In order to do this, processes should be synchronized in some way. 2/15/2022
Engineered for Tomorrow Unit-III Process Synchronization • • Background The Critical Section Problem Peterson’s Solution Synchronization hardware Semaphores Classical problems of synchronization Monitors 2/15/2022
Engineered for Tomorrow Critical-Section Problem § Suppose a system has n processes{P 0, P 1, …Pn-1). § Each process has a segment of code, called a critical section. § Processes perform operations – changing common variables, updating a table, writing a file § When one process is executing in its critical section, no other process is allowed to execute in its critical section. § Problem – design a protocol that the processes can use to co-operate. § Each process must request permission to enter its critical section. § Entry section - section of code implementing this request 2/15/2022
Engineered for Tomorrow § Exit section – follows critical section § Remainder section – contains the remaining code § General structure of a typical process, Pi 2/15/2022
Engineered for Tomorrow Requirements for solving the 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 2. Progress - If no process is executing in its critical section and some processes wish to enter their critical section, then the selection of the processes that will enter the critical section, can be decided by - only those processes that are not executing in their remainder sections. 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 2/15/2022
Engineered for Tomorrow Approaches to handle critical sections i)pre-emptive kernels § Allows a process to be pre-empted, while it is running in kernel mode. § Difficult to design for SMP architectures. ii)non-preemptive kernels § Does not allow a process running in kernel mode to be pre-empted. § A kernel-mode process will run until Ø it exits kernel mode Ø blocks Ø voluntarily releases the control of CPU 2/15/2022
Engineered for Tomorrow Q: Why is a pre-emptive kernel preferred over a nonpreemptive kernel for real-time programming? A: A pre-emptive kernel allows a real-time process to pre-empt a process currently running in the kernel. § A pre-emptive kernel can be more responsive. 2/15/2022
Engineered for Tomorrow Solutions to Critical Section Problem § Peterson’s solution § Synchronization hardware 2/15/2022
Engineered for Tomorrow Unit-III Process Synchronization • • Background The Critical Section Problem Peterson’s Solution Synchronization hardware Semaphores Classical problems of synchronization Monitors 2/15/2022
Engineered for Tomorrow Peterson’s Solution • Consider 2 processes that alternate execution between their critical sections & remainder sections. • Processes are numbered Pi and Pj. • These processes share 2 data items: int turn; boolean flag[2]; § Variable turn indicates, whose turn it is to enter the critical section. § If turn==i, then process Pi is allowed to execute in its critical section. § The flag array is used to indicate if a process is ready to enter its critical section. § Ex: If a flag[i]=true, then Pi is ready to enter its critical section. 2/15/2022
Engineered for Tomorrow General structure of a typical process, Pi : do { flag[i] = TRUE; turn = j; while (flag[j] && turn == j); critical section flag[i] = FALSE; remainder section } while (TRUE); 2/15/2022
Engineered for Tomorrow • By setting flag[i]=true and turn=j, process Pi asserts that any other process can enter the critical section, if it wants. § The final value of turn determines, which of the 2 processes is allowed to enter the critical section first. § Peterson’s solution should satisfy 3 requirements to prove its correctness : Ø Mutual exclusion is preserved Ø The progress requirement is satisfied. Ø The bounded-waiting requirement is met. 2/15/2022
Engineered for Tomorrow i)Property 1 – Each process, Pi enters its critical section only, if either flag[j]==false or turn==i. ii) Properties 2 & 3 – A process, Pi can be prevented from entering the critical section only, if it is stuck in the while loop condition, flag[j]==true and turn==j. 2/15/2022
Engineered for Tomorrow Unit-III Process Synchronization • • Background The Critical Section Problem Peterson’s Solution Synchronization hardware Semaphores Classical problems of synchronization Monitors 2/15/2022
Engineered for Tomorrow Synchronization Hardware • Peterson’s solution do not work on modern computer architectures. • Race conditions are prevented- by protecting critical regions using locks. • A process must acquire a lock, before entering a critical section, & release the lock before exiting the critical section. do { acquire lock critical section release lock remainder section } while (TRUE); § Drawback – Complicated for application programmers to use 2/15/2022
Engineered for Tomorrow Implementation of locks in multi-processor environment : § Special hardware instructions Ø test & modify the content of a word – Test. And. Set() Ø swap the contents of two words atomically- Swap() 2/15/2022
Engineered for Tomorrow § Definiton- Test. And. Set() instruction : boolean Test. And. Set (boolean *target) { boolean rv = *target; *target = TRUE; return rv: } § Definition – Swap() instruction void Swap (boolean *a, boolean *b) { boolean temp = *a; *a = *b; *b = temp: } 2/15/2022
Engineered for Tomorrow Algorithms for satisfying the mutual-exclusion requirement of critical-section problem i) Mutual-exclusion implementation using Test. And. Set() ii) Mutual-exclusion implementation with Swap() function i) Mutual-exclusion implementation using Test. And. Set() do { while ( Test. And. Set (&lock )) ; // do nothing // critical section lock = FALSE; // remainder section } while (TRUE); 2/15/2022
Engineered for Tomorrow ii) Mutual-exclusion implementation with Swap() function do { key = TRUE; while ( key == TRUE) Swap (&lock, &key ); // critical section lock = FALSE; // } while (TRUE); 2/15/2022 remainder section
Engineered for Tomorrow Implementation of Test. And. Set() & Swap(), satisfying all requirements of critical-section problem : § 2 data structures are initialized to false : boolean waiting[n]; boolean lock; § Mutual exclusion requirement – a process can enter its critical section only if waiting[i]==false or key==false. § Progress requirement – A process exiting the critical section sets lock==false or waiting[j]==false. § Bounded-waiting requirement – When a process leaves its critical section, it Ø scans the array – waiting Ø sets the first process in the array, waiting[j]==true 2/15/2022
Engineered for Tomorrow Bounded-waiting mutual exclusion with Test. And. Set() do { waiting[i] = TRUE; key = TRUE; while (waiting[i] && key) key = Test. And. Set(&lock); waiting[i] = FALSE; // critical section j = (i + 1) % n; while ((j != i) && !waiting[j]) j = (j + 1) % n; if (j == i) lock = FALSE; else waiting[j] = FALSE; // remainder section } while (TRUE); 2/15/2022
Engineered for Tomorrow Unit-III Process Synchronization • • Background The Critical Section Problem Peterson’s Solution Synchronization hardware Semaphores Classical problems of synchronization Monitors 2/15/2022
Engineered for Tomorrow Semaphores • • Usage Implementation Deadlocks & Starvation Priority Inversion 2/15/2022
Engineered for Tomorrow Definition § A Semaphore, S is an integer variable that can be accessed only through atomic operations (excluding initialization) wait() signal() § wait() operation, termed as P, defined as wait (S) { while S <= 0 ; // no-op S--; } § Signal() operation, termed as V, defined as signal (S) { S++; } 2/15/2022
Engineered for Tomorrow Usage § Counting semaphore - can range over an unrestricted domain used to control access to a given resource with finite no. of instances. A process wishing to use a resource, performs a wait() operation on the semaphore. A process wishing to release a resource, performs signal() operation on the semaphore. § Binary semaphore - can range between 0 & 1. Mutex locks- another name of binary semaphores. Provide mutual exclusion. 2/15/2022
Engineered for Tomorrow • Mutual-exclusion implementation with mutex do { wait (mutex); // Critical Section signal (mutex); // remainder section } while (TRUE); 2/15/2022
Engineered for Tomorrow Implementation § Drawbacks of wait() and signal() semaphores: When a process is in its critical section, any other process that tries to enter critical section , must loop continuously in the entry code. Ø Known as busy waiting, a problem in real multiprogramming system. Ø Spinlocks - Busy waiting wastes CPU cycles, that some other process may use productively. - This type of semaphore is called spinlock. - The process spins waiting for the lock. - Advantage- No context-switch is required, while a process waits for the lock. Ø 2/15/2022
Engineered for Tomorrow § Solution : Implement a semaphore using a waiting queue Ø Modify the definition of wait() & signal() semaphore operations. Ø A process that is blocked, is restarted when some other process executes a signal() operation. Ø wakeup() operation changes the process from waiting state to ready state. Ø A semaphore is defined as a “C” struct : typedef struct{ int value; struct process *list; } semaphore; 2/15/2022
Engineered for Tomorrow Ø Each semaphore has an integer value & a list of processes. Ø When a process has to wait for a semaphore, it is added to the list of processes. Ø A signal() operation removes one process from the list of waiting processes & awakens that process. Ø wait() is re-defined as : wait(semaphore *S) { S->value--; if (S->value < 0) { add this process to S->list; block(); } } 2/15/2022
Engineered for Tomorrow Ø signal() is re-defined as signal(semaphore *S) { S->value++; if (S->value <= 0) { remove a process P from S->list; wakeup(P); } } Ø List of waiting processes is implemented by a link field in each process control block(PCB). Ø Bounded waiting of processes in the list is ensured by using a FIFO queue. 2/15/2022
Engineered for Tomorrow Deadlocks & starvation § Implementation of a semaphore with a waiting queue may result in a situation where 2 or more processes are waiting indefinitely for the execution of a signal() operation. § When such a state is reached, processes are said to be deadlocked. § Consider a system consisting of two processes, P 0 & P 1, each accessing 2 semaphores- S & Q, set to value, 1 : P 0 P 1 wait (S); wait (Q); wait (S); . . . signal (S); signal (Q); signal (S); 2/15/2022
Engineered for Tomorrow • Suppose P 0 executes wait(S) & then P 1 executes wait(Q). • When P 0 executes wait(Q), it must wait until, P 1 executes signal(Q). • When P 1 executes wait(S), it must wait until P 0 executes signal(S). • Since these signal operations cannot be executed, P 0 & P 1 are deadlocked. • Starvation(indefinite blocking) – processes wait indefinitely within the semaphore. Ø Processes are removed from the list associated with a semaphore in LIFO order. 2/15/2022
Engineered for Tomorrow Priority Inversion § A higher-priority process needs to access kernel data, currently being accessed by a lower-priority process. § Since kernel data will be locked, the higher-priority process has to wait for the lower-priority process to finish. § Assume 3 processes – L, M, H whose priorities follow the order L< M<H. § Assume process H requires resource R, currently being accessed by process, L. § Usually, H has to wait until L finishes. § Suppose process, M becomes runnable, by pre-empting process, L. § Now process, H has to wait until both M & L finish. 2/15/2022
Engineered for Tomorrow • Priority inheritance Ø All the processes that are accessing resources needed by a higher-priority process, inherit the higher priority until, they finish. Ø When they finish, their priorities revert to their original values. Ø In the example, process L is allowed to inherit the priority of process H, temporarily. Ø This prevents L from pre-empting to M. Ø After L finishes, it assumes its original priority. Ø Now resource will be available to H, not M. 2/15/2022
Unit-III Process Synchronization Engineered for Tomorrow • • Background The Critical Section Problem Peterson’s Solution Synchronization hardware Semaphores Classical problems of synchronization Monitors 2/15/2022
Engineered for Tomorrow Classic Problems of Synchronization • The Bounded-Buffer Problem • The Readers-Writers Problem • The Dining-Philosophers Problem 2/15/2022
Engineered for Tomorrow Bounded- Buffer Problem § A buffer pool consists of n buffers, each capable of holding 1 item. § Mutex semaphore provides mutual exclusion for accesses to the buffer pool & is initialized to 1. § empty semaphore – counts the no. of empty buffers, initialized to n. § full semaphore- counts the no. of full buffers, initialized to 0. 2/15/2022
Engineered for Tomorrow Structure of the producer process do { // produce an item in nextp wait (empty); wait (mutex); // add the item to the buffer signal (mutex); signal (full); } while (TRUE); 2/15/2022
Engineered for Tomorrow Structure of the consumer process do { wait (full); wait (mutex); // remove an item from buffer to nextc signal (mutex); signal (empty); // consume the item in nextc } while (TRUE); 2/15/2022
Engineered for Tomorrow Readers-Writers Problem § Readers – Processes which only want to read the database. § Writers – Processes which want to update(read/write) the database. § Two readers accessing the shared database- no problem § A writer & other process(reader/writer) accessing the shared database- lots of problems. § Writers should have exclusive access to the shared database, while writing into it. § This synchronization problem is known as Readers. Writers problem. 2/15/2022
Engineered for Tomorrow Variants of Readers-Writers problem § There are 2 variants to this problem: i) No reader should be kept waiting, unless a writer has obtained permission to use the shared object. ii) Once a writer is ready, the writer should perform the writer as soon as possible. 2/15/2022
Engineered for Tomorrow Solution for variant 1: i) The reader processes share the following data structures: semaphore mutex, wrt; int readcount; § Semaphores mutex & wrt are initialized to 1, readcount is initialized to 0. § readcount variable – keeps track of how many processes are currently reading the object. § wrt – functions as a mutual-exclusion semaphore for the writers. 2/15/2022
Engineered for Tomorrow Structure of a writer process do { wait (wrt) ; // writing is performed signal (wrt) ; } while (TRUE); 2/15/2022
Engineered for Tomorrow Structure of a reader process do { wait (mutex) ; readcount ++ ; if (readcount == 1) wait (wrt) ; signal (mutex) // reading is performed wait (mutex) ; readcount - - ; if (readcount == 0) signal (wrt) ; signal (mutex) ; } while (TRUE); 2/15/2022
Engineered for Tomorrow Solution to Readers-Writers problem using locks § Reader-Writer locks are provided on some systems. § Acquiring readers-writers locks, requires specifying the mode of the lock: read or write access § If a process wishes to read from a shared database, it requests for a reader-writer lock in read mode. § If a process wishes to modify the shared data, it requests for a reader-writer lock in write mode. § Reader-writer locks are useful in following situations: Ø In applications, where its easy to identify processes which want only to read or only to write. Ø In applications, having more readers than writers. 2/15/2022
Engineered for Tomorrow Dining-Philosophers Problem • Philosophers spend their lives thinking and eating • Don’t interact with their neighbors, occasionally try to pick up 2 chopsticks, that are closest to her(chopsticks that are between her & her left & right neighbor). • Can pick up only one chopstick at a time. • Cannot pick up a chopstick, that is already in the hand of a neighbor. 2/15/2022
Engineered for Tomorrow • When a philosopher has both the chopsticks, she eats without releasing them. • As she finishes eating, she puts down both her chopsticks & starts thinking again. • This problem represents the need to allocate several resources among several processes in a deadlock-free & starvation-free manner. 2/15/2022
Engineered for Tomorrow Solution § Represent each chopstick with a semaphore. § A philosopher gets a chopstick, by executing wait() operation on appropriate semaphores. § Releases a chopstick, by executing signal() operation on appropriate semaphores. § Shared data are : semaphore chopstick[5]; where all the elements of chopstick are initialized to 1. § Drawback – may create a deadlock 2/15/2022
Engineered for Tomorrow Structure of a philosopher, i : do { wait ( chopstick[i] ); wait ( chop. Stick[ (i + 1) % 5] ); // eat signal ( chopstick[i] ); signal (chopstick[ (i + 1) % 5] ); // think } while (TRUE); 2/15/2022
Engineered for Tomorrow Remedies to overcome deadlock § Allow at-most 4 philosophers to be sitting simultaneously at the table. § Allow a philosopher to pick up her chopsticks, only if both the chopsticks are available. § Use an asymmetric solution Ø An odd philosopher first picks up her left chopstick & then her right. Ø An even philosopher first picks up her right chopstick & then her left. 2/15/2022
Engineered for Tomorrow Unit-III Process Synchronization • • Background The Critical Section Problem Peterson’s Solution Synchronization hardware Semaphores Classical problems of synchronization Monitors 2/15/2022
Engineered for Tomorrow Monitors § § Usage Dining-Philosophers solution using Monitors Implementing a Monitor using Semaphores Resuming Processes within a Monitor 2/15/2022
Engineered for Tomorrow Drawbacks of synchronization using semaphores: • Incorrect use of semaphores, result in timing errors that are difficult to detect. • Timing errors occur in any of the following situations: i) Suppose a process interchanges the order, in which wait() & signal() operations on the semaphore mutex are executed. Mutual exclusion requirement is violated. signal(mutex); ……. critical section ……. wait(mutex); 2/15/2022
Engineered for Tomorrow ii) Suppose a process replaces signal(mutex) with wait(mutex). A deadlock occurs. wait(mutex); ……. . critical section. ……. . wait(mutex); iii) Suppose a process omits the wait(mutex) or the or both. § Mutual exclusion requirement is violated or deadlock may occur. 2/15/2022
Engineered for Tomorrow Usage § A monitor type is an abstract data type, which presents a set of programmer-defined operations , that provide mutual-exclusion. § An abstract data type, encapsulates private data with public methods, to operate on that data. § Ensures that only 1 process is active at a time within the monitor. 2/15/2022
Engineered for Tomorrow • Syntax of a monitor-name { // shared variable declarations procedure P 1 (…) { …. } procedure P 2 (…) { …. }. . . procedure Pn (…) { …… } initialization code (…) { …… } } 2/15/2022
Engineered for Tomorrow Fig: Schematic view of a monitor 2/15/2022
Engineered for Tomorrow Monitor with condition variables § Monitor construct alone is not powerful for modeling & synchronization. § Additional synchronization mechanism such as condition construct is used. condition x, y; § Only operations that can be invoked on a condition variable are – wait() & signal() x. wait() - a process that invokes the operation is suspended until x. signal () x. signal()- resumes one of processes (if any) that invoked x. wait () 2/15/2022
Engineered for Tomorrow Fig: Schematic view of a Monitor with condition variables 2/15/2022
Engineered for Tomorrow • If process P invokes x. signal (), with Q in x. wait () state, what should happen next? – If Q is resumed, then P must wait • Options include – Signal and wait – P waits until Q leaves monitor or waits for another condition – Signal and continue – Q waits until P leaves the monitor or waits for another condition – Both have pros and cons – language implementer can decide 2/15/2022
Engineered for Tomorrow Dining Philosophers solution using Monitors § Imposes the restriction, that a philosopher may pick up her chopsticks only if both are available. § Introduce the following data structure: enum {THINKING, HUNGRY, EATING} state[5]; § Philosopher i, sets the variable state[i]= EATING, only if her 2 neighbors are not eating. § A philosopher I, delays herself when she is hungry, but unable to get the chopsticks she needs by declaring condition self[5]; 2/15/2022
Engineered for Tomorrow monitor Dining. Philosophers { 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 left and right neighbors test((i + 4) % 5); test((i + 1) % 5); } 2/15/2022
Engineered for Tomorrow void test (int i) { if ( (state[(i + 4) % 5] != EATING) && (state[i] == HUNGRY) && (state[(i + 1) % 5] != EATING) ) { state[i] = EATING ; self[i]. signal () ; } } initialization_code() { for (int i = 0; i < 5; i++) state[i] = THINKING; 2/15/2022
Engineered for Tomorrow Implementing a Monitor using Semaphores § Variables semaphore mutex; // (initially = 1) semaphore next; // (initially = 0) int next_count = 0; § A process executes wait(mutex) – before entering the monitor signal(mutex) – after leaving the monitor § Signaling processes can use next to suspend themselves. § next_counts the no. of processes suspended on next. 2/15/2022
Engineered for Tomorrow • Each procedure F will be replaced by wait(mutex); … body of F; … if (next_count > 0) signal(next) else signal(mutex); Monitor Implementation using Condition Variables • For each condition variable x, we have: semaphore x_sem; // (initially = 0) int x_count = 0; 2/15/2022
Engineered for Tomorrow • Operation x. wait is implemented as x_count++; if (next_count > 0) signal(next); else signal(mutex); wait(x_sem); x-count--; • The operation x. signal can be implemented as: if (x-count > 0) { next_count++; signal(x_sem); wait(next); next_count--; } 2/15/2022
Engineered for Tomorrow Resuming Processes within a Monitor • If several processes queued on condition x, and x. signal() executed, which should be resumed? • FCFS frequently not adequate • conditional-wait construct of the form x. wait(c) – Where c is priority number – Process with lowest number (highest priority) is scheduled next 2/15/2022
Engineered for Tomorrow Resource Allocator Monitor monitor Resource. Allocator { boolean busy; condition x; void acquire(int time) { if (busy) x. wait(time); busy = TRUE; } void release() { busy = FALSE; x. signal(); } initialization code() { busy = FALSE; } 2/15/2022
Engineered for Tomorrow • A process that needs to access the resource must observe the following sequence: R. acquire(t); …… access the resource; …… R. release(); where R is an instance of type Resource Allocator 2/15/2022
Engineered for Tomorrow Drawbacks of Monitor § A process might access a resource, without first gaining access permission to the resource. § A process might never release a resource, once it has been granted access to the resource. § A process might attempt to release a resource that it never requested. § A process might request the same resource twice. 2/15/2022
- Slides: 76