Download presentation
Presentation is loading. Please wait.
Published byLiliana Johns Modified over 9 years ago
1
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science Software Systems Advanced Synchronization Emery Berger and Mark Corner University of Massachusetts Amherst
2
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science 2 Why Synchronization? Synchronization serves two purposes: –Ensure safety for shared updates Avoid race conditions –Coordinate actions of threads Parallel computation Event notification ALL interleavings must be correct –there are lots of interleavings of events –also constrain as little as possible
3
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science 3 Synch. Operations Safety: –Locks provide mutual exclusion Coordination: –Condition variables provide ordering
4
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science 4 Safety Multiple threads/processes –access shared resource simultaneously Safe only if: –All accesses have no effect on resource, e.g., reading a variable, or –All accesses idempotent E.g., a = abs(x), a = highbit(a) –Only one access at a time: mutual exclusion
5
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science 5 “The too much milk problem” Model of need to synchronize activities Safety: Example
6
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science 6 thread A if (no milk && no note) leave note buy milk remove note thread B if (no milk && no note) leave note buy milk remove note Does this work? too much milk Why You Need Locks
7
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science 7 Mutual Exclusion Prevent more than one thread from accessing critical section –Serializes access to section Lock, update, unlock: –lock (&l); –update data; /* critical section */ –unlock (&l);
8
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science 8 thread A lock(&l) if (no milk) buy milk unlock(&l) thread B lock(&l) if (no milk) buy milk unlock(&l) Too Much Milk: Locks
9
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science What data is shared? Some data is shared –code, data, heap Each thread has private data –Stack, SP, PC All access to shared data must be safe
10
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science 10 Exercise! Simple multi-threaded program –N = number of iterations –Spawn that many threads to compute value = expensiveComputation(i) –Add value (safely!) to total Use: –pthread_mutex_init, _lock, _unlock pthread_mutex_t myLock; –pthread_create, pthread_join pthread_t threads[N];
11
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science pthread_t theseArethreads[100]; pthread_mutex_t thisIsALock; typedef void * fnType (void *); pthread_create (pthread_t *, NULL, fnType, void *); pthread_join (pthread_t, void *); pthread_mutex_init (pthread_mutex_t *, NULL) pthread_mutex_lock (pthread_mutex_t *) pthread_mutex_unlock (pthread_mutex_t *) 11 Prototypes
12
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science 12 #include int total = 0; pthread_mutex_t lock; void * wrapper (void * x) { int v = *((int *) x); delete ((int *) x); int res = expComp (v); pthread_mutex_lock (&lock); total += res; pthread_mutex_unlock (&lock); return NULL; } int main (int argc, char * argv[]) { int n = atoi(argv[1]); // mutex init pthread_mutex_init (&lock); // allocate threads pthread_t * threads = new pthread_t[n]; // spawn threads for (int i = 0; i<n; i++) { // heap allocate args int * newI = new int; *newI = i; pthread_create (&threads[i], NULL, wrapper, (void *) newI); } // join for (int i = 0; i<n; i++) { pthread_join (threads[i], NULL); } // done printf (“total = %d\n”, total); return 0; } Solution
13
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science 13 Synch. Operations Safety: –Locks provide mutual exclusion Coordination: –Condition variables provide ordering
14
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science 14 Synch Problem: Queue Suppose we have a thread-safe queue –insert(item), remove(), empty() –must protect access with locks Options for remove when queue empty: –Return special error value (e.g., NULL) –Throw an exception –Wait for something to appear in the queue
15
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science Three Possible Solutions Spin –Works? Could release lock –Works? Re acquire Lock lock(); while(empty()) {} unlock(); v = remove(); unlock(); while(empty()) {} lock(); v = remove(); lock() while (empty()) { unlock(); lock(); } V = remove(); unlock();
16
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science Solution: Sleep! Sleep = –“don’t run me until something happens” What about this? Cannot hold lock while sleeping! Dequeue(){ lock(); if (queue empty) { sleep(); } take one item; unlock(); } Enqueue(){ lock(); insert item; if (thread waiting) wake up dequeuer(); unlock(); }
17
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science Quick Exercise Does this work? Dequeue(){ lock(); if (queue empty){ unlock(); sleep(); remove item; } else unlock; } Enqueue(){ lock(); insert item; if (thread waiting) wake up dequeuer(); unlock(); } No! – deq releases lock, then enq looks for sleeping thread
18
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science Condition Variables Make it possible/easy to go to sleep –Atomically: release lock put thread on wait queue go to sleep Each cv has a queue of waiting threads Worry about threads that have been put on the wait queue but have NOT gone to sleep yet? –no, because those two actions are atomic Each condition variable associated with one lock
19
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science 19 Condition Variables Wait for 1 event, atomically release lock –wait(Lock& l, CV& c) If queue is empty, wait –Atomically releases lock, goes to sleep –You must be holding lock! –May reacquire lock when awakened (pthreads do) –signal(CV& c) Insert item in queue –Wakes up one waiting thread, if any –broadcast(CV& c) Wakes up all waiting threads Monitors = locks + condition variables –Sometimes combined with data structures
20
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science Condition Variable Exercise Implement “Producer Consumer” –One thread enqueues, another dequeues void * consumer (void *){ while (true) { pthread_mutex_lock(&l); while (q.empty()){ pthread_cond_wait(&nempty, &l); } cout << q.pop_back() << endl; pthread_mutex_unlock(&l); } Two Questions? –Can I use if instead of while (to check cond)? –Can I signal after unlock? void * producer(void *){ while (true) { pthread_mutex_lock(&l); q.push_front (1); pthread_cond_signal(&nempty); pthread_mutex_unlock(&l); }
21
U NIVERSITY OF M ASSACHUSETTS A MHERST Department of Computer Science Bounded-Buffer Exercise Implement “Producer Consumer” –One thread enqueues, another dequeues void * consumer (void *){ while (true) { pthread_mutex_lock(&l); while (q.empty()){ pthread_cond_wait(&nempty, &l); } cout << q.pop_back() << endl; pthread_cond_signal(&nfull); pthread_mutex_unlock(&l); } void * producer(void *){ while (true) { pthread_mutex_lock(&l); while (q.size() == N) { pthread_cond_wait(&nfull,&l); } q.push_front (1); pthread_cond_signal(&nempty); pthread_mutex_unlock(&l); }
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.