You are on page 1of 28
Operating Systems Inter-Processes Communication Outline ¢ Introduction * Race condition * Critical region ¢ Process synchronization Introduction * Processes within a system may be independent or cooperating + Reasons for cooperating processes — Information sharing — Computation speedup — Modularity — Convenience * Cooperating processes frequently need to communicate => inter-process communication (IPC) — Communicate without using interrupts * Issues related to IPC — How one process can pass information to another process — Howto make sure two or more processes do not get in each other’s way * E.g., two or more processes in an airline reservation system trying to take the last seat on a plane for different customers — Proper sequencing when dependencies are present * E.g., Output of one process is an input for the other * Question 7] | = i apply to threads? Explain. 3 Race condition * Is where two or more processes are reading or writing some shared data and the final result depends on who runs precisely when * Undesirable behavior that can occur from inappropriate reliance on ordering of operations * Example: Print spooler = Shared variables + out points to the next file to be printed + in points to the next free slot in the directory — Processes A and B want to queue a file for printing — Each process reads in and stores the value in a local variable called next_free_slot an es ‘La ais [] | | | | Se . . Race condition... ¢ What happens when a race condition occurs? — System hangs — System crashes — Lost data — Security problems — Unpredictability Critical regions * What shall we do to avoid race condition? — Find some way to prohibit more than one process from reading and writing the shared data at the same time = ie., conflicting sections should be mutually exclusive * Critical region/section — Part of the program where the shared memory is accessed * Conditions to enable parallel processes cooperate correctly and efficiently using shared data, i.e., requirements for a critical section implementation 1. No two processes may be simultaneously inside their critical section 2. No assumption may be made about the speeds or the number of CPUs 3. No process outside its critical section (including the entry and exit code)may block other processes 4. No process should have to wait forever to enter its critical section Ae SMEAEIE uae cea gon {tener | ses [] | | | | soa “ : Process synchronization * Approaches to achieve mutual exclusion * Disabling interrupt — Disable all interrupts just after entering its critical region and re-enable them just before leaving it — No clock interrupts can occur — Simple — Not a good choice. Why? * Gives user processes the power to turn off interrupts * Doesn’t work in a system with multiprocessor — Disabling interrupts affects only the CPU that executes the disable instruction, other processes on other CPUs could access it Process synchronization... * Local variables — Uses a single, shared (lock) variable * Set variable to 0 => indicates no process in the critical section * Set variable to 1 => some process in the critical section * Same problem as the printer spooler example above — Using two shared variables * Example: software solution (mutual exclusion with busy waiting) Initially Plwants-P2wants=false code for P2 code for Pz Loop forever ¢ Loop forever { Plvants <-- true ENTRY Povants <-- true while (Pawants) {} ENTRY while (Plwants) {+ critical-section critical-section Plwants <-- false EXIT Pavants <-- false non-critical-section } non-critical-section } — Does the above code work? Why? Process synchronization... * Strict alteratio’ in — Aprocess enters a critical section, after checking value of turn — If its not the processes turn, the process continuously tests turn — Busy waiting * Continuously test a variable until some value appears * Should usually be avoided — Problem * When one of the processes are slower than the other. Violates requirement 3 whi } le (TRUE) { while (turn != 0) critical_region( ); tum =1; noneritical_region(); (a) loop */ ; while (TRUE) { while (turn != 1) f* loop #/; critical_region(); turn = 0; noneritical_region( ); } (b) Process synchronization... * Dekker’s solution — First correct solution — Combines the idea of — fsineraur | taking turns with the iidefineN 2 idea of wants ewe; — Idea int interested{N}; * Take turns where there void enter_region(int process); is contention, but when { there is no contention, int other; the requesting process other = 1 — provess; can enter interested[process] = TRUE; * Peterson’s solution ———— — Same as Dekker’s ) solution but simpler void leave_region(int process) ( } Interested[process] = FALSE; / number of processes */ 7+ whose turn is it? #/ /+ all values initially 0 (FALSE) +/ /+ process is 0 or 1 +/ /+ number of the other process */ /* the opposite of process */ 7+ stow that you are interested +/ 7m set flag #/ process && interested[other] == TRUE) /+ null statement +/; /+ process: who is leaving +/ /+ indicate departure from critical region + 10 — Supported by the hardware Process synchronization... * The TSL instruction — Some computers, esp. those with multiprocessors have instructions like * TSL, RX, LOCK — Test and Set Lock * Reads the contents of the memory word lock into register RX and then stores a nonzero value at the memory address lock * Operations of reading the word and storing into RXare atomic operations — CPU executing the TSL instruction locks the memory bus to prohibit other CPUs from accessing memory until its done * NB. — Locking memory bus is different from disabling interrupts enter_region: TSL REGISTER,LOCK CMP REGISTER, #0 JNE enter_region RET leave_region: MOVE Locicaa | copy lock to register and set lock to 1 | was lock zero? [if it was not zero, lock was set, so loop | return to caller; critical region entered | store a 0 in lock n [return to caller Process synchronization... * Sleep and wakeup — What is limitation of TSL and Peterson’s solutions? * Requires busy waiting * Priority inversion problem — Two processes with different priority — Low priority process gets access to critical section — High priority process becomes ready to access the critical section — The scheduling algorithm could block the process with low priority » ie., low priority process gets blocked in its critical section — Inter-process communication primitives * Sleep — Causes the caller to block or suspend until another process wakes it up * Wakeup — Unblocks a process that is blocked or suspended Process synchronization... * Sleep and wakeup... — Producer-consumer problem * Also known as bounded-buffer problem Two processes share a common, fixed-size buffer. One of them, the producer, puts information into the buffer, and the other one, the consumer, takes it out * Problem 1. Producer wants to put a new item in the buffer, but it is already full » Soln.: Producer goes to sleep 2. Consumer wants to remove an item from the buffer and sees that the buffer is empty » Soln.: Consumer goes to sleep [] | | | | * Process synchronization... * Sleep and wakeup... — Producer-consumer problem . ‘define N 100 int count = 0; void producer(void) intitern; while (TRUE) { item = produce _item(); 1) sleep}; Void consumer(void) { int item; while (TRUE) { if (count ‘consume _item(item); } } Wa = 1) wakeup(producer); ‘J+ numberof slots in the butter »/ ‘+ umber of items inthe buflor */ J» repeat forever +/ ‘fr generate next item + ‘if uteri ful, goto sleep +/ ‘f» put item in butter */ ‘+ increment count of items in buffer #/ ‘f+ was butter empty? +! Js repeat forever +/ ‘=f buffer is empty, got to sleep */ ‘take item out of buffer */ ‘f+ decrement count of items in buffer +/ ‘was butler full? #/ Js print iter #/ 14 Process synchronization... * Sleep and wakeup... — Producer-consumer problem ... * Race condition — Buffer status: Empty 1. 2. 3. 4. 5s. Consumer has just read count to see if it is 0 Scheduler decides to stop running the consumer temporarily and start running the producer Producer inserts an item in the buffer, increments count, and calls wakeup to wake consumer (which is going to be lost) Scheduler starts consumer, consumer sees count = 0 and sleeps Producer fill up the buffer and also go to sleep => Both will sleep forever * — Solution Add a wakeup waiting bit » Set when a wakeup is sent to a process that is still awake » — Aprocess will check this bit before going to sleep + Ifon, process will stay awake and turn off the bit [] | | | | * Process synchronization... * Semaphores — Uses an integer variable called semaphore as a flag that can be accessed through two atomic operations * Semaphore = 0 => no wakeups were saved * Semaphore > 0 => if one or more wakeups were pending — Operations on semaphore * Generalizations of sleep and wakeup * down — Checks to see if the value is greater than 0 — If semaphore > 0, process decrements value and continues — If semaphore = 0, process goes to sleep without completing the down * up — Increments the value of the semaphore addressed — One of the sleeping processes is chosen by the system randomly and allowed to complete down * Atomic operations — Checking the value, changing it, and possibly going to sleep Process synchronization... * Semaphores... teen 10 — Producer-consumer problem snspoaero * Semaphore could be used to solve intitem; the lost-wakeup problem (sleep while (TRUE) { wakeup example — see the code) ° How? cout = count — Implement up and down in an See indivisible way } — Each semaphore should be protected {**°™s7er“o? by a lock variable with TSL intitem; instructions while (TRUE) ( » TSL prevent several CPUs from Teale reneve chem accessing the semaphore for count=count—1; short period of time if (coun 1) wakeup(produ consume _item(item); } [] | | | | Batt vemma abe 0) y Process synchronization... * Semaphores... — Producer-consumer problem + Semaphore use — Mutual exclusion » Mutex = Synchronization » Full and empty semaphores ‘define N 100 ‘/ number of slots in the buffer */ typedef int semaphore; ‘x semaphores are a special kind of int / semaphore mutex = 1 J» controls access to critical region */ semaphore empl J» counts empty buffer slots */ semaphore full = 0; + counts full butfer slots +/ void producer(void) voi consumers) intitem: int tem; while (TRUE) { “inti top»! while (TRUE) { J TRUE i the constant «/ TRU nie ate item = produce item); /* generate something to put in buffer */ Sown(&mutex) + enter critical region */ down(empty): ‘+ decrement empty count +/ item = femove.item() take tem rom butter */ down(&mutex); ‘/* enter critical region */ up(&mutex); + leave critical region */ insert tomitern; put new tem in butfer«/ eeonot “increment oun of empty ots + up(&mutex); f+ leave critical region +/ ‘consume _itemyitem); + do something with the item +/ plat): 7 increment count of fl slots */ : } } [] Hi || | * Process synchronization... Mutex — Simplified version of semaphore * Noneed to count — Good for managing mutual exclusion to some shared resource or piece of code — Isashared variable that can be in one of two states: * Unlocked * Locked — Omeans unlocked and all other values means locked — Call mutex lock to enter a critical region rmutex_lock TSLREGISTER.MUTEX | copy mutex to register and set mutex to 1 CMP REGISTER, #0 | was mutex zero? JZE ok [if twas zero, mutex was unlocked, so return CALL thread_yield | mutex is busy; schedule another thread IMP mutex-iock | try again ok RET. | return to caller; eriical region entered ‘mutex_unlock: MOVE MUTEX,#0 | store a 0 in mutex ms (ste loa = » Process synchronization... * Assumption in proposed solutions — Requires for multiple processes to have access to at least some shared memory — BUT processes have disjoint address spaces * Question — How can they share the turn variable in Peterson’s algorithm, or semaphores or a common buffer? ¢ Answer 1. Semaphores can be stored in the kernel and accessed only by means of system calls 2. Most modern OSs offer a way for processes to share some portion of their address space with other processes Using shared files [] = | | * Process synchronization... * Monitors — Scenario (while using semaphore) + Buffer full ‘define N 100 ‘* number of slots in the buffer +*/ 1. Swap empty and mutex _typedet int semaphore; ‘+ semaphores are a special kind of int +/ semaphores semaphore mutex = 1; ‘+ controls access to critical region +/ semaphore empty = N; ‘+ counts empty bulfer sits +! 2. Producer executes semaphore full = 0; ‘+ counts full butter slots +! 3. Consumer executes void producervoi) — What would happen? (tem * Deadlock : while (TRUE) { ‘/* TRUE is the constant 1 4/ item = produce item): /* generate something to put in buffer */ _ ‘down(&empt ‘+ decrement empty count «/ Shows that one must be down(&mutes ‘/* enter critical region */ very careful insert_item(item); _/* put new item in butter +/ up(&mutex); ‘+ leave crtical region +! up(&full); ‘/* increment count of full slots */ = Solution )? 2 Process synchronization... * Monitors... Are a collection of procedures, variables, and data structures that are all grouped together in a special kind of module or package Processes can call procedures in monitors but cannot access the monitors internal data structure monitor example Syntax: nameOfMonitor.procedureName integer i: condition ¢; Only one process can be active in a monitor at any instance procedure producer( ); + When a process calls a monitor procedure = Checks if any other process is in the monitor = Ifs0, the calling process will be suspended until the other finishes end: = Otherwise, calling process enters the monitor procedure consumer): Monitors are programming language constructs Compiler is responsible to achieve mutual exclusion on end; monitor entries end monitor; + Could use mutex or binary semaphore [] | | | | 2 Process synchronization... * Monitors... — Semantics * The monitors procedures are accessible by all the processes of the system * The data in the monitor is shared among processes * Variables of the monitor can only be accessed through the procedures of the monitor — We use conditionals using the “condition” type declaration — Operations on variables of “condition” type * Wait (variable): blocks the calling process on that specific condition * Signal(variable): wakes a process sleeping on a condition variable 23 Process synchronization... ¢ Monitors... — What happens after a signal? * How to avoid having two active processes in the monitor at the same time? — Proposal * Let the newly awakened process run, suspending the other process in the monitor * Aprocess doing signal must exit the monitor immediately * Let the signaler continue to run and allow the waiting process to start running only after the signaler has exited the monitor 24 Monitors... — Producer consumer problem with monitors Process synchronization... — Difference of wait and signal from sleep and wakeup + Problem: = sleep and wakeup failed because while one process was trying to go to sleep, the other was trying to wake it up = This cant happen with monitors monitor ProducerConsumer condition full, empny: Integer count, procedure inseri(item: integer, begin If count = N then wait(ful); insert ttem( item); “ount + 1; 1 then signalempry) function remove: integer; begin iff count = 0 then wait(emprs): remove = remove item; count == count — 1; if count = N— 1 then signal/full) end: count := 0; ‘end monitor; procedure producer: begin while rrue do ProducerConsumerinsertitem) end end: procedure consimner: Ddegin while rrue do. begin item = ProducerConsumersemove; consume —itemt item) end end; 25 Process synchronization... ¢ Monitors... — Java supports monitors * Synchronized — Java guarantees that once any thread has started executing that method, no other thread will be allowed to start executing any other synchronized method of that object 26 Process synchronization... ¢ What do you need to know while solving a synchronization problem? — What are the processes that need to be blocked? — What are the conditions for blocking? — Who should unblock the process and when? Process synchronization... * Classical IPC problem — The dining philosophers problem * Aclassical problem from Dijkstra — 5 philosophers sitting at a round table » Thinking or eating — Each has a plate of spaghetti — There is a fork between each two — Need two forks to eat — Acquires one fork at a time in either right to left or left to right order * What algorithm do you use for access to the shared resource (the forks)? [] | | | | *

You might also like