CS 423 Operating System Design: Sy Sync nchr hroniz nizatio ion Tianyin Tianyin Xu Xu * Thanks for Prof. Adam Bates for the slides. CS423: Operating Systems Design
Please post the topic you’d like me to chat about in the first 10 minutes on Piazza! CS423: Operating Systems Design
Th Than anks ks Yi YiFei ei an and d Ha Haoqing ing an and d many oth man y other ers w s who ar o are h e hel elping g oth others on on P Piazza! azza! (I promise I will buy you beers after I come back!) CS423: Operating Systems Design
Synchronization Motivation CS423: Operating Systems Design 4
Can this panic? CS423: Operating Systems Design 5
Why Reordering? CS423: Operating Systems Design 6
Too Much Milk! CS423: Operating Systems Design 7
Too Much Milk! SOLUTION Make your own oat milk at home srsly tho — https://minimalistbaker.com/make-oat-milk/ CS423: Operating Systems Design 8
Definitions CS423: Operating Systems Design 9
Too Much Milk, Try #1 CS423: Operating Systems Design 10
Too Much Milk, Try #2 CS423: Operating Systems Design 11
Too Much Milk, Try #3 CS423: Operating Systems Design 12
Takeaways CS423: Operating Systems Design 13
Synchronization Roadmap CS423: Operating Systems Design 14
Locks CS423: Operating Systems Design 15
Too Much Milk, Try #4 CS423: Operating Systems Design 16
Ex: Lock Malloc/Free CS423: Operating Systems Design 17
Rules for Using Locks CS423: Operating Systems Design 18
Ex: Thread-Safe Bounded Queue CS423: Operating Systems Design 20
Question(s) CS423: Operating Systems Design 21
Implementing Locks • Take 1: using memory load/store • See too much milk solution/Peterson’s algorithm • Take 2: • Lock::acquire() • Lock::release() CS423: Operating Systems Design 22
Lock Implementation for Uniprocessor? Lock::release() { Lock::acquire() { disableInterrupts(); disableInterrupts(); if (!waiting.Empty()) { if (value == BUSY) { next = waiting.remove(); waiting.add(myTCB); next->state = READY; myTCB->state = WAITING; readyList.add(next); next = readyList.remove(); switch(myTCB, next); } else { value = FREE; myTCB->state = RUNNING; } } else { enableInterrupts(); value = BUSY; } } enableInterrupts(); } CS423: Operating Systems Design 23
Condition Variables • Waiting inside a critical section • Called only when holding a lock • CV::Wait — atomically release lock and relinquish processor • Reacquire the lock when wakened • CV::Signal — wake up a waiter, if any • CV::Broadcast — wake up all waiters, if any CS423: Operating Systems Design 24
Condition Variables methodThatSignals() { methodThatWaits() { lock.acquire(); lock.acquire(); // Read/write shared state // Read/write shared state // If testSharedState is now true while (!testSharedState()) { cv.signal(&lock); cv.wait(&lock); } // Read/write shared state // Read/write shared state lock.release(); lock.release(); } } CS423: Operating Systems Design 25
Ex: Bounded Queue w/ CV get() { put(item) { lock.acquire(); lock.acquire(); while (front == tail) { while ((tail – front) == MAX) { empty.wait(lock); full.wait(lock); } } item = buf[front % MAX]; buf[tail % MAX] = item; front++; tail++; full.signal(lock); empty.signal(lock); lock.release(); lock.release(); return item; } } Initially: front = tail = 0; MAX is buffer capacity empty/full are condition variables CS423: Operating Systems Design 26
Pre/Post Conditions • What is state of the bounded buffer at lock acquire? • front <= tail • front + MAX >= tail • These are also true on return from wait • And at lock release • Allows for proof of correctness CS423: Operating Systems Design 27
Pre/Post Conditions methodThatWaits() { methodThatSignals() { lock.acquire(); lock.acquire(); // Pre-condition: State is consistent // Pre-condition: State is consistent // Read/write shared state // Read/write shared state while (!testSharedState()) { // If testSharedState is now true cv.wait(&lock); cv.signal(&lock); } // WARNING: shared state may // NO WARNING: signal keeps lock // have changed! But // testSharedState is TRUE // Read/write shared state // and pre-condition is true lock.release(); } // Read/write shared state lock.release(); } CS423: Operating Systems Design 28
Condition Variables • ALWAYS hold lock when calling wait, signal, broadcast • Condition variable is sync FOR shared state • ALWAYS hold lock when accessing shared state • Condition variable is memoryless • If signal when no one is waiting, no op • If wait before signal, waiter wakes up • Wait atomically releases lock • What if wait, then release? • What if release, then wait? CS423: Operating Systems Design 29
Condition Variables • When a thread is woken up from wait, it may not run immediately • Signal/broadcast put thread on ready list • When lock is released, anyone might acquire it • Wait MUST be in a loop while (needToWait()) { condition.Wait(lock); } • Simplifies implementation • Of condition variables and locks • Of code that uses condition variables and locks CS423: Operating Systems Design 30
Mesa vs. Hoare Semantics • Mesa • Signal puts waiter on ready list • Signaller keeps lock and processor • Hoare • Signal gives processor and lock to waiter • When waiter finishes, processor/lock given back to signaller • Nested signals possible! CS423: Operating Systems Design 31
FIFO Bounded Queue (Hoare Semantics) put(item) { get() { lock.acquire(); lock.acquire(); if ((tail – front) == MAX) { if (front == tail) { full.wait(lock); empty.wait(lock); } } buf[last % MAX] = item; item = buf[front % MAX]; last++; front++; empty.signal(lock); full.signal(lock); // CAREFUL: someone else ran lock.release(); lock.release(); return item; } } Initially: front = tail = 0; MAX is buffer capacity empty/full are condition variables CS423: Operating Systems Design 32
FIFO Bounded Queue (Mesa Semantics) • Create a condition variable for every waiter • Queue condition variables (in FIFO order) • Signal picks the front of the queue to wake up • CAREFUL if spurious wakeups! •Easily extends to case where queue is LIFO, priority, priority donation, … •With Hoare semantics, not as easy CS423: Operating Systems Design 33
Synchronization Best Practices • Identify objects or data structures that can be accessed by multiple threads concurrently • Add locks to object/module • Grab lock on start to every method/procedure • Release lock on finish • If need to wait • while(needToWait()) { condition.Wait(lock); } • Do not assume when you wake up, signaller just ran • If do something that might wake someone up • Signal or Broadcast • Always leave shared state variables in a consistent state • When lock is released, or when waiting CS423: Operating Systems Design 35
Remember the rules… • Use consistent structure • Always use locks and condition variables • Always acquire lock at beginning of procedure, release at end • Always hold lock when using a condition variable • Always wait in while loop CS423: Operating Systems Design 36
Recommend
More recommend