CS 162 Lecture Notes for Wenesday, Feb.04, 2009 Transcribed by Noah(Xixiang) Xing, based on lecture notes by Prof. Smith ************************* *** Atomic operations *** ************************* Atomic Operations - in order to synchronize parallel processes at operation that either happens in the entirety without interruption, or not at all. Atomic operations cannot be interrupted in the middle. Loads and assignments are atomic in almost all system. a=b will always get a good value for b and will always set a good value for a. Correctness is not an issue of atomic operations, but done or not done is. In uniprocessor system, turning off interrupts can make what is between off/on atomic (note that i/o can interfere, and some interrupts are not maskable and traps can't be turned off). ******************************************* *** Synchronization, the too-much-milk problem *** ******************************************* The problem needs a correction solution of getting exactly one unit of milk. 1st attempt: processes a&b if (no milk) { if (no note) { leave note; buy milk; remove note; } } Problem from this attempt: a & b may both place a note without noticing the other party standing nearby. A basic problem is that a sequence of operations can be interrupted at any time. If both switch after reading the if statement, both will buy milk. Any such interruption must be accounted for in order to get correct results. Result: this doesnĄ¯t always work Synchronization behaviors are using atomic op to ensure correct operations of cooperating processes. One of the tools to synchronization: Mutual exclusion: mechanism that ensures that only one person or process is doing certain things at one time, others are excluded. Critical section: a collection of operations, in which only one process may be executing at a given time. E.g. shopping; code manipulates the state at a time. E.g. bank account There are many ways to achieve mutual exclusion. Most of them involve some sort of locking mechanism: (prevent multiple processes from using a critical section at the same time) three elements of locking: 1. must lock before using/doing leave note 2. must unlock when done. Remove note 3. must wait if locked. Don't shop if note 2nd attempt: change meaning of note. Processor a buys if there is no note. Processor b buys if there is a note. This gets rid of confusion. When milk is desired, the procedure is executed prosA if (no note) if(noMilk) buy milk; leave note; prosB if (note) if (noMilk) buy milk; remove note; Q: A student asks about the situation when one roommate (prosA or prosB) goes spring break. A: If b goes on vocation, notes never removed. This causes a of starvation. Result: needs a reliable roommate to make this work. The conditions for correctness is 1) if there is no milk , someone will buy it. 2) at most one unit of milk will be purchased. 3rd attempt: use 2 notes proc a leave noteA if(no noteB) { if (no mlik) { buy milk; } } remove noteA proc b leave noteB if(no noteA) { if(no milk) { buy milk; } remove noteB At most one process will buy milk. Each proc leaves note before it checks. If one goes on vacation after step9 (removing notes), the other will buy milk. But suppose both a & b leave note at exactly the same time, no body will buy milk. -> still starvation. The solution is almost correct. 4th attempt: in case of tie, a will buy milk. proc a leave noteA; while (noteB) { does nothing; } if (no milk) { buy milk; } remove noteA proc b leave noteB; if (no noteA) { if (no milik) { buy milk; } } remove noteB; This solution works, but has disadvantages. a may have to wait while b is at the store. While a is waiting, it is consuming resources (busy-waiting). Also, consider the possibility of "death" in critical section and the possibility of a third roommate. For synchronization problems, it is hard to tell if getting a solution. E.g. a third roommate in the milk problem. Requirement for a mutual exclusion mechanism: must allow only one process into a critical section at a time, if that is what is desired (mutual exclusion)(critical section is that part of the process that does stuff that can't be interrupted). If several request at once, must allow one process to proceed. Process must be able to go on vacation, being outside of critical section. Desireable properties for a mutual exclusiton mech: no indefinite postponement. i.e. no individual processes efficient: don't use up substantail amount of resource simple. should be easy to use critical section: only one process How mutual exclusion mechanism should be used: always lock before manipulate shared data always unlock after manipulating shared data. do note&lock again if already locked do not unlock unless you are supposed to (usually, unless you locked it) do not spend large amount of time in critical section no failures in critical section. e.g. don't go on vacation ************************************************************ *** Synchronizations with Semaphores, Threads, Conditons variables *** ************************************************************ Mutual exclusion mechanism was too simple -minded. It used only atomic reads and writes (leaving notes). This is sufficient, but unpleasant. And it is unbearable to extend that mechanism to many processes. *Higher level mechanism* Semaphore is a synchronization variable that takes on non-negative integer values. Running process is actively recycling CPU cycles. Blocked process is not able to run. Because it is waiting for something e.g. i/o synchronization, etc. p(probveren=test)): an atomic operation that attempts to decrement a semaphore. If the semaphore is positive, it succeeds. If the semaphore is 0, the process is blocked until some other process increments it. v(semaphore): an atomic operation on a semaphore. If there is at least one process blocked on this semaphore, one is released. Otherwise , the semaphore is incremented v(verhogen=increment) *There is no current machine that implements semaphore. It experimental ly solves synchronization problems. ***************************************** *** too much milk problems with semaphores *** ***************************************** proc a&b 1 .p(OKtoBuyMilk); 2. if(no milk) buyMilk; 3. v(OKtoBuyMilk); critical section is between p & v, assuring critical section is not interrupted. (If a large critical section, the code may not be able to be debugged, locking the system down. Such a critical section is very insufficient.) Binary semaphores use only 0 and 1. Counting semaphores are semaphores whose value is used as a count of some sort. Semaphores are not provide by hardware, but they have several attractive properties: machine independent; simple; powerful; embody both exclusion and waiting; correctness is relative easy to determine. Semaphore solution usually work for n processes, not just 2. You can have many different critical sections with different semaphores. Semaphore is used in two different ways. Mutual exclusion: to ensure that one process is accessing shared info at a time. If separate groups of data that can be accessed independently, there may be separate semaphores, one for each group of data. Scheduling: to permit process to wait for certain thing to happen. *semaphore examples* producer & consumer is an example having one producer and one consumer that share a buffer. The producer writes data into the buffer and the consumer reads data from the buffer. The constraints here are that producer does not write when the buffer is full and consumer does not read when the buffer is empty. Initialization: put all buffers in pool of empties; initialize semaphore: empties=N, fulls=0, mutex=1; producer process: p(empties); p(mutex); v(mutex); get empty buffer from pool of empties; v(mutex); produce data in buffer; p(mutex); add full buffer to pool of fulls; v(mutex); v(fulls); consumer process p(fulls); p(mutex); get full buffer from pool of fulls; v(mutex); consume data in buffer; p(mutex); add empty buffer to pool of empties; v(mutex); v(empties); Q: a student asks about two mutexes in the above case. A: Having two separate lists of buffers. The order matters to avoid deadlock happened. important questions: Why does producer p(empties) but v(fulls)? Producer gains a lock to modify the pool of empty, but it release the other so that consumer can gains a lock to modify the pool of full. Why is order of p's important? If producer locks a critical section and waits for an empty buffer, consumer cannot access the critical section to modify. Thus consumer cannot add empty buffer to pool of empties -> Deadlock. Is order of v's important? No. v means releasing a lock and it does not matter which lock is released first. Could we have separate semaphores for each pool? Yes, in fact, it would be more efficient, if the pools were separate, would have mutex1 and mutex2 How would this be extended to have 2 (or N) consumers? Have two or more pools, one semaphore for each pool.