b8f53d3547a93bfe5d0c1f9bf8af9fb3.ppt
- Количество слайдов: 30
Operating Systems Design (CS 423) Elsa L Gunter 2112 SC, UIUC http: //www. cs. illinois. edu/class/cs 423/ Based on slides by Roy Campbell, Sam King, and Andrew S Tanenbaum 3/15/2018 1
Synchronizing multiple threads n Must control interleaving between threads n Order of some operations irrelevant n n n Independent Other operations are dependent and order does matter All possible interleaving must yield a correct answer n A correct concurrent program will work no matter how fast the processors are that execute the various threads 3/15/2018 2
Synchronizing multiple threads n n n All interleavings result in correct answer Try to constrain the thread executions as little as possible Controlling the execution and order of threads is called “synchronization” 3/15/2018 3
Too much milk n n n The Gunter household drinks a lot of milk, but has a small fridge Problem: Carl and Elsa want there to always at least one gallon of milk in the fridge for dinner; fridge holds at most two gallons If either sees there is less than one gallon, goes to buy milk Specification: Someone buys milk if running low Never more than two gallons of milk 3/15/2018 4
Solution #0 – no sync Carl 5: 30 5: 35 5: 40 5: 45 5: 50 5: 55 6: 00 6: 05 6: 10 Elsa Comes home Checks milk Goes to store Buys milk Goes home Puts milk in Fridge 3/15/2018 Comes home Checks milk Goes to store Buys milk Comes home Too much milk! 5
Mutual Exclusion n Ensure that only 1 thread is doing a certain thing at one time n n Only one person goes shopping at one time Critical section n A section of code that needs to run atomically w. r. t. other code If code A and code B are critical sections w. r. t. each other threads cannot interleave events from A and B Critical sections must be atomic w. r. t. each other n n Share data (or other resourced, e. g. , screen, fridge) What is the critical section in solution #0? 3/15/2018 6
Too much milk (solution #1) n n n Assume only atomic operations are load and store Idea: leave note that going to check on milk status Carl: if (no note) {if (milk low) {leave note; buy milk; remove note; } Elsa: if (no note) {if (milk low) {leave note; buy milk; remove note; } What can go wrong? Is this better than before? 3/15/2018 7
Too much milk (solution #2) n n n Idea: Change order of leave note and check milk Carl: if (milk low) {if (no note) {leave note; buy milk; remove note; } Elsa: if (milk low) {if (no note) {leave note; buy milk; remove note; } What can go wrong? Is this better than before? 3/15/2018 8
Too much milk (solution #3) n n n Idea: Protect more actions with note Carl: if (no note) {leave note; if (milk low) {buy milk}; remove note; } Elsa: if (no note) {leave note; if (milk low) {buy milk}; remove note; } What can go wrong? Is this better than before? 3/15/2018 9
Too much milk (solution #4) n n n Idea: Change order of leaving note and checking note Carl: leave note. Carl; if (no note. Elsa) { if (milk low) {buy milk}; } ; remove note. Carl Elsa: leave note. Elsa; if (no note. Carl) { if (milk low) {buy milk}; } ; remove note. Elsa What can go wrong? Is this better than before? 3/15/2018 10
Too much milk (solution #5) n n n Idea: When both leave note, always give priority to fixed one to buy milk Carl: leave note. Carl; while (note. Elsa) {do nothing}; if (milk low) {buy milk}; remove note. Carl Elsa: leave note. Elsa; if (no note. Carl) { if (milk low) {buy milk}; } ; remove note. Elsa Simplified instance of Bakery Algorithm 3/15/2018 11
Too much milk (solution #5) n n while (note. Elsa) for Carl prevents him from buying milk at same time as Elsa Proof of correctness n n n Two parts: Will never have two people buying milk at same time Will always have someone able to buy milk if it is needed Correct, but ugly n Complicated, Asymmetric, Inefficient n Carl wastes time while waiting (Busy Waiting) 3/15/2018 12
Higher-level synchronization n n Problem: could solve “too much milk” using atomic loads/stores, but messy Solution: raise the level of abstraction to make life easier for the programmer Concurrent programs High-level synchronization provided by software Low-level atomic operations provided by hardware 3/15/2018 13
Locks (mutexes) A lock is used to prevent another thread from entering a critical section n Two operations n Lock(): wait until lock is free, then acquire do {if (lock == LOCK_FREE) { lock = LOCK_SET; break; } } while(1) n Unlock(): lock = LOCK_FREE n 3/15/2018 14
Locks (mutexes) n n Why was the “note” in Too Much Milk solutions #1 and #2 not a good lock? Four elements of using locks n n n Lock is initialized to be free Acquire lock before entering a critical section Wait to acquire lock if another thread already holds Release lock after exiting critical section All synchronization involves waiting Thread can be running, or blocked (waiting) 3/15/2018 15
Locks n n Locks -- shared variable among all thread Multiple threads share locks n n Only affects threads that try to acquire locks Important: Lock acquisition is atomic! 3/15/2018 16
Lock Variables n n Critical section -- part of the program where threads access shared (global) state Locks -- shared variables used to enforce mutual exclusion n Can have multiple lock variables 3/15/2018 17
Locks (mutexes) n Locks make “Too Much Milk” really easy to solve! Elsa: Carl: lock(frigdelock); if (milk low) {buy milk} unlock(fridgelock) Correct but inefficient n How to reduce waiting for lock? How to reduce time lock is held? n 3/15/2018 18
Too Much Milk – Solution 7 Does the following work? lock(); if (milk low & no note) { leave note; unlock(); buy milk; remove note; } else { unlock() } n 3/15/2018 19
Too Much Milk – Solution 7 Does the following work? lock(); if (milk low & no note) { leave note; unlock(); buy milk; lock(); remove note; unlock(); } else { unlock() } n 3/15/2018 20
Queues without Locks enqueue (new_element, head) { // find tail of queue for(ptr=head; ptr->next != NULL; ptr = ptr->next); // add new element to tail ptr->next = new_element; new_element->next = NULL; } 3/15/2018 21
Queues without Locks dequeue(head, element) { element = NULL; // if something on queue, remove it if(head->next != NULL) { element = head->next; head->next = head->next; } return element; } n What bad things can happen if two threads manipulate the queue at the same time? 3/15/2018 22
Thread-safe Queues with Locks enqueue (new_elt, head) { lock(queuelock); // find tail of queue for(ptr=head; ptr->next != NULL; ptr = ptr->next); // add new element to tail ptr->next = new_elt; new_elt->next = NULL; unlock(queuelock); } 3/15/2018 dequeue(head, elt) { lock(queuelock); element = NULL; // remove if possible if(head->next != NULL) { elt = head->next; head->next = head->next; } unlock(queuelock); return elt; } 23
Invariants for multi-threaded queue n Can enqueue() unlock anywhere? n Stable state called an invariant n n I. e. , something that is “always” true Is the invariant ever allowed to be false? 3/15/2018 24
Invariants for multi-threaded queue n n In general, must hold lock when manipulating shared data What if you’re only reading shared data? 3/15/2018 25
Enqueue – Can we do better? enqueue() { lock find tail of queue unlock add new element to tail of queue unlock } n Is this better? 3/15/2018 26
Dequeue if empty? n n What if you wanted to have dequeue() wait if the queue is empty? Could spin in a loop: dequeue() { lock(queuelock); element = NULL; while (head-next == NULL) {wait; }; if(head->next != NULL) { element = head->next; head->next = head->next; } unlock(queuelock); return element; } 3/15/2018 27
Problem lock(queuelock); … while (head-next == NULL) {wait; }; n n n Holding lock while waiting No one else can access list (if they observe the lock) Wait forever 3/15/2018 28
Dequeue if empty – Try 2 Could release the lock before spinning: lock(queuelock); … unlock(queuelock); while (head-next == NULL) {wait; }; n n Will this work? 3/15/2018 29
Dequeue if empty – Try 3 Could release lock and acquire lock on every iteration lock(queuelock); … while (head-next == NULL) {unlock(queuelock); }; n This will work, but very ineffecient. n 3/15/2018 30


