Software Systems Advanced Synchronization

21
UNIVERSITY OF NIVERSITY OF MASSACHUSETTS ASSACHUSETTS AMHERST MHERST Department of Computer Science Department of Computer Science Software Systems Advanced Synchronization Emery Berger and Mark Corner University of Massachusetts Amherst

description

Software Systems Advanced Synchronization. Emery Berger and Mark Corner University of Massachusetts Amherst. Why Synchronization?. Synchronization serves two purposes: Ensure safety for shared updates Avoid race conditions Coordinate actions of threads Parallel computation - PowerPoint PPT Presentation

Transcript of Software Systems Advanced Synchronization

Page 1: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science Department of Computer Science

Software SystemsAdvanced Synchronization

Emery Berger and Mark CornerUniversity of Massachusetts

Amherst

Page 2: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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

Page 3: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science Department of Computer Science 3

Synch. Operations Safety:

– Locks provide mutual exclusion Coordination:

– Condition variables provide ordering

Page 4: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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

Page 5: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science Department of Computer Science 5

“The too much milk problem”

Model of need to synchronize activities

Safety: Example

Page 6: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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

Page 7: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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);

Page 8: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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

Page 9: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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

Page 10: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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];

Page 11: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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

Page 12: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science Department of Computer Science 12

#include <pthread.h>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

Page 13: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science Department of Computer Science 13

Synch. Operations Safety:

– Locks provide mutual exclusion Coordination:

– Condition variables provide ordering

Page 14: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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

Page 15: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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();

Page 16: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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();}

Page 17: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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

Page 18: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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

Page 19: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science 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

Page 20: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science Department of Computer Science

Condition Variable Exercise Implement “Producer Consumer”

– One thread enqueues, another dequeuesvoid * 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); }}

Page 21: Software Systems Advanced Synchronization

UUNIVERSITY OF NIVERSITY OF MMASSACHUSETTS ASSACHUSETTS AAMHERST • MHERST • Department of Computer Science Department of Computer Science

Bounded-Buffer Exercise Implement “Producer Consumer”

– One thread enqueues, another dequeuesvoid * 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); }}