
cafc8ec77db405ce52c9f068fb180bed.ppt
- Количество слайдов: 35
Pthread (continue) • General pthread program structure – Encapsulate parallel parts (can be almost the whole program) in functions. – Use function arguments to parameterize what a particular thread does. • Usually needs to know myid and nprocs. • Add synchronization when necessary – Call pthread_create() with the function and arguments, save thread identifier returned. – Call pthread_join() with that thread identifier
Thread synchronizations • When more than one thread works on the same task, the threads often need to coordinate their activities to ensure correct behavior. – Coordination that results in synchronization or communication is the inherent price to pay when going multithreading. • Coordination often means waiting!
Motivating Example: Too Much Milk • Two robots are programmed to maintain the milk inventory at a store… • They are not aware of each other’s presence… Robot: Dumber
Motivating Example: Too Much Milk Dumb 4: 00 Look into fridge: Out of milk Dumber
Motivating Example: Too Much Milk Dumb 4: 00 Look into fridge: Out of milk 4: 05 Head for the warehouse Dumber
Motivating Example: Too Much Milk Dumb 4: 05 Head for the warehouse Dumber 4: 10 Look into fridge: Out of milk
Motivating Example: Too Much Milk Dumber 4: 10 Look into fridge: Out of milk 4: 15 Head for the warehouse
Motivating Example: Too Much Milk Dumb 4: 20 Dumber 4: 15 Head for the warehouse Arrive with milk
Motivating Example: Too Much Milk Dumb 4: 20 Dumber 4: 15 Head for the warehouse Arrive with milk
Motivating Example: Too Much Milk Dumb 4: 20 Arrive with milk 4: 25 Go party Dumber
Motivating Example: Too Much Milk Dumb 4: 20 Arrive with milk 4: 25 Go party Dumber 4: 30 Arrive with milk: “Uh oh…”
Common coordination constructs • Critical section: a piece of code that only one thread can execute at a time – Only one thread can go get milk at one time. • Mutual exclusion: ensure one thread can do something without the interference of other threads – When I print, nobody else should be printing.
Common coordination constructs • Synchronization: use atomic operations to ensure cooperation among threads – Event synchronization T 1 … X = 400 … T 2 … Y = X+1. . . T 1 … X = 400 X ready … … T 2 … …. wait for X Y=X+1. . .
Pthreads synchronization support • Mutex locks – Critical session and mutual exclusion • Condition variables – Event synchronization • Semaphores – Both (in UNIX, not pthread)
Mutex locks: lock/unlock • pthread_mutex_lock(pthread_mutex_t *mutex); – Tries to acquire the lock specified by mutex – If mutex is already locked, then the calling thread blocks until mutex is unlocked. • At one time, only one thread can get the lock
Mutex locks: lock/unlock • pthread_mutex_unlock(pthread_mutex_t *mutex); – If the calling thread has mutex currently locked, this will unlock the mutex. – If other threads are blocked waiting on this mutex, one will unblock and acquire mutex. – Which one is determined by the scheduler.
Lock and critical section • A lock prevents a thread from doing something – A thread should lock before entering a critical section – A thread should unlock when leaving the critical section – A thread should wait if the critical section is locked • Synchronization often involves waiting
Mutex lock– for mutual exclusion int counter = 0; void *thread_func(void *arg) { int val; /* unprotected code – why? */ val = counter; counter = val + 1; return NULL; }
Mutex example int counter = 0; ptread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void *thread_func(void *arg) { int val; /* protected by mutex */ Pthread_mutex_lock( &mutex ); val = counter; counter = val + 1; Pthread_mutex_unlock( &mutex ); return NULL; }
Condition variables – and event synchronization • Think of Producer – consumer problem • Producers and consumers run in separate threads. • Producer produces data and consumer consumes data. • Producer has to inform the consumer when data is available • Consumer has to inform producer when buffer space is available
Condition variables: wait • Pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) – Blocks the calling thread, waiting on cond. – Unlock the mutex – Re-acquires the mutex when unblocked.
Condition variables: signal • Pthread_cond_signal(pthread_cond_t *cond) – Unblocks one thread waiting on cond. – The scheduler determines which thread to unblock. – If no thread waiting, then signal is a no-op
Producer consumer program without condition variables
/* Globals */ int data_avail = 0; pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER; void *producer(void *) { Pthread_mutex_lock(&data_mutex); Produce data Insert data into queue; data_avail=1; Pthread_mutex_unlock(&data_mutex); }
void *consumer(void *) { while( !data_avail ); /* do nothing – keep looping!!*/ Pthread_mutex_lock(&data_mutex); Extract data from queue; if (queue is empty) data_avail = 0; Pthread_mutex_unlock(&data_mutex); consume_data(); }
Producer consumer with condition variables
int data_avail = 0; pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cont_t data_cond = PTHREAD_COND_INITIALIZER; void *producer(void *) { Pthread_mutex_lock(&data_mutex); Produce data Insert data into queue; data_avail = 1; Pthread_cond_signal(&data_cond); Pthread_mutex_unlock(&data_mutex); }
void *consumer(void *) { Pthread_mutex_lock(&data_mutex); while( !data_avail ) { /* sleep on condition variable*/ Pthread_cond_wait(&data_cond, &data_mutex); } /* woken up */ Extract data from queue; if (queue is empty) data_avail = 0; Pthread_mutex_unlock(&data_mutex); consume_data(); }
A note on condition variables • A signal is forgotten if there is no corresponding wait that has already occurred. • If you want the signal to be remembered, use semaphores.
Semaphores • Counters for resources shared between threads. Sem_wait(sem_t *sem) – Blocks until the semaphore vale is non-zero – Decrements the semaphore value on return. Sem_post(sem_t *sem) – Unblocks the semaphore and unblocks one waiting thread – Increments the semaphore value otherwise
Pipelined task parallelism with semaphore P 1: for (I=0; I
Challenges with thread programming • Race condition: occurs when multiple threads and write to the same memory location. – Solution with a coordination mechanism: lock, conditional variable, semaphore, etc • Coordination results in waiting among threads – Deadlocks: occur when threads are waiting for resources with circular dependencies
Deadlock example T 1: … Lock(printer) … Lock (keyboard) … Unlock(printer) T 2: … lock(keyboard) … lock(printer) … unlock(keyboard)
Deadlock and third party software • In sequence programs, using third party software is trivial. – Call “system(“/usr/bin/ls”); – No knowledge about /usr/bin/ls is needed. • Could deadlock happen in thread programming by calling a third party program? – This is a big problem facing multi-thread programming.
Summary • What is thread coordination (synchronization)? Why? • What are the common thread coordinations? • Pthread’s support for thread coordination. – Mutex lock – Condition variable • Deadlock • Thread programming issues