1 / 21

Synchronization

Synchronization. Where are we going with synchronization?. We are going to implement various higher-level synchronization primitives using atomic operations Everything is pretty painful if only atomic primitives are load and store Need to provide primitives useful at user-level. Programs.

Download Presentation

Synchronization

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Synchronization

  2. Where are we going with synchronization? We are going to implement various higher-level synchronization primitives using atomic operations Everything is pretty painful if only atomic primitives are load and store Need to provide primitives useful at user-level Programs Higher-level API Hardware Shared Programs Locks Semaphores Monitors Load/Store Disable Ints Test&Set Comp&Swap

  3. Lock • Race conditions can be prevented by requiring that critical sections be protected by locks. That is, a process must acquire a lock before entering a critical section; it releases the lock when it exits the critical section

  4. Synchronization do { [acquire lock] critical section [release lock] remainder section } while (TRUE);

  5. “Too Much Milk” Solution #4 Suppose we have some sort of implementation of a lock Lock.Acquire() – wait until lock is free, then grab Lock.Release() – Unlock, waking up anyone waiting These must be atomic operations – if two processes are waiting for the lock and both see it’s free, only one succeeds to grab the lock Then, our milk problem is easy: milklock.Acquire(); if (nomilk) buy milk; milklock.Release();

  6. How to implement Locks? • Lock: prevents someone from doing something • Lock before entering critical section and before accessing shared data • Unlock when leaving, after accessing shared data • Wait if locked • Important idea:all synchronization involves waiting • Should sleep if waiting for a long time • Hardware Lock instruction

  7. Synchronization Hardware • Many systems provide hardware support for critical section code • Uniprocessors – could disable interrupts • Currently running code would execute without preemption • System’s clock is kept updated by interrupts

  8. Naïve use of Interrupt Enable/Disable • How can we build multi-instruction atomic operations? • Recall: dispatcher gets control in two ways • Internal: Process does something to relinquish the CPU • External: Interrupts cause dispatcher to take CPU • On a uniprocessor, can avoid context-switching by: • Avoiding internal events (although virtual memory tricky) • Preventing external events by disabling interrupts • Consequently, naïve implementation of locks: LockAcquire { disable Ints; } LockRelease { enable Ints; } • Problems with this approach: • Can’t let user do this! Consider following: LockAcquire();While(TRUE) {;} • What happens with I/O or other important events? • “Reactor about to meltdown. Help?”

  9. Synchronization Hardware • Modern machines provide special atomic hardware instructions • Atomic = non-interruptable • Atomic instructions that allow us either to test and modify the content of a word or to swap the contents of two words

  10. Synchronization Hardware • Test and modify the content of a word atomically booleanTestAndSet(boolean &target) { booleanrv = target; target = true; return rv; }

  11. Mutual Exclusion with Test-and-Set • Shared data: boolean lock = false; • Process Pi do { while (TestAndSet(lock)); critical section lock = false; remainder section } while (TRUE);

  12. Synchronization Hardware • Atomically swap two variables void Swap(boolean &a, boolean &b) { boolean temp = a; a = b; b = temp; }

  13. Mutual Exclusion with Swap • Shared data (initialized to false): boolean lock; • Process Pi do { key = true; // key is a local variable while (key == true) Swap(lock,key); critical section lock = false; remainder section } while (TRUE);

  14. Bounded-waiting Mutual Exclusion with TestandSet() do { waiting[i] = TRUE; key = TRUE; while (waiting[i] && key) key = TestAndSet(&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);

  15. Semaphores • Dijkstra’s work on semaphores established over 30 years ago the foundation of modern techniques for accomplishing synchronization • A semaphore, S, is a integer variable that is changed or tested only by one of the two following indivisible operations P(S): while (S 0) do no-op; S--; V(S): S++; • In Dijkstra’s original paper, the P operation was an abbreviation for the Dutch word Proberen, meaning “to test” and the Voperation was an abbreviation for the word Verhogen, meaning “to increment” • Now, P() and V() is normally called wait() and signal()

  16. Critical Section for n Processes • Shared data: semaphoremutex; //initially mutex= 1 • Process Pi do { P(mutex);critical section V(mutex);remainder section} while (TRUE);

  17. Semaphore Implementation • Must guarantee that no two processes can execute wait () and signal () on the same semaphore at the same time • Thus, implementation becomes the critical section problem where the wait and signal code are placed in the crtical section. • Could now have busy waiting in critical section implementation • But implementation code is short • Little busy waiting if critical section rarely occupied • Note that applications may spend lots of time in critical sections and therefore this is not a good solution.

  18. Semaphore Implementation with no Busy waiting • With each semaphore there is an associated waiting queue. Each entry in a waiting queue has two data items: • value (of type integer) • pointer to next record in the list typedef struct { int value; struct process *L; } semaphore; • Two operations: • block – place the process invoking the operation on the appropriate waiting queue. • wakeup – remove one of processes in the waiting queue and place it in the ready queue.

  19. Semaphore Implementation • Semaphore operations now defined as P(S): S.value--; if (S.value< 0) { add this process toS.L;block(); } V(S): S.value++; if (S.value<= 0) { remove a process PifromS.L;wakeup(Pi); }

  20. Semaphore as a General Synchronization Tool • Execute <B> in Pjonly after <A> executed in Pi • Use semaphore flaginitialized to 0 Pi Pj <A> P(flag) V(flag) <B>

  21. 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 • Starvation – indefinite blocking. A process may never be removed from the semaphore queue in which it is suspended • Let S and Qbe two semaphores initialized to 1 Pi Pj P(S) P(Q) P(Q) P(S) V(S) V(Q) V(Q) V(S)

More Related