180 likes | 323 Views
Chapter 6. P-Threads. Names. The naming convention for a method/function/operation is: pthread_ thing _ operation (..) Where thing is the object used (such as mutex , condition, etc ) o peration is what to do (such as init , lock, etc )
E N D
Chapter 6 P-Threads
Names • The naming convention for a method/function/operation is: • pthread_thing_operation(..) • Where thing is the object used (such as mutex, condition, etc) • operation is what to do (such as init, lock, etc) • To operate on the thread itself, leave off the thing • Such as pthread_create, pthread_join • Types end in _t rather than the operation
Create a Thread • intpthread_create(pthread_t *TID, constpthread_attr_t *attr, void * (*start_routine)(void *), void *arg) • TID – thread identifier • attr – a pthread attribute object (can be NULL for default values) • start_routine – the name of the function for the new thread to start execution at. • arg – the argument to pass to the starting function. Use a struct if want to pass more than 1 value
Thread operations • pthread_tpthread_self() – returns thread id of the current thread. • intpthread_equal(pthread_t t1, pthread_t t2) – returns 0 if t1 and t2 are not the same thread, returns not 0 otherwise. • intsysconf(_SC_THREAD_THREADS_MAX) • Returns the maximum number of threads the system can handle • Not a pthreads function but a system call • Google sysconf for more functionality
Coordinating Threads • intpthread_join(pthread_t TID, void **valuep) • Waits until thread TID has completed (no wait if it has already completed • valuep has the value returned by the function the thread started • If several threads are waiting for the same thread, only one of the waiting threads get the return value. Others have a value returned by pthread_join being ESRCH (from errno.h)
Ending a Thread • Explicitly • Calling pthread_exit(void *valuep) to exit and return the value • return • Implicitly • pthread_exit() called implicitly when function terminates • Remember all local variable are destroyed.
Sidenote – faking a 2-D array with 1-D • Want an array A(m, n); fake with B(m*n) • Using a row major ordering, A(i,j) is at B(i*n+j) • Using column major, A(i,j)is at B(i+j*m) • Look at figure 6.1 together
Thread Coordination • Need to be able to restrict a variable to exclusive use in order to prevent race conditions • Pthreads uses 2 things: mutex and condition variables
Mutex type • To get a mutex variable declare it of type pthread_mutex_t • Mutex variables have 2 states, locked and unlocked • Need a mutex variable for each memory area that you want to allow mutually exclusive access. This association is implied by program coding. Can make it more explicit by grouping the mutex variable with its associated mutually exclusive structure into the same struct
Mutex Use • For mutually exclusive use, every thread must • Lock the mutex before using the structure • If successful, this thread is the owner of the mutex variable • After finishing mutually exclusive use of the memory area, the thread must unlock the mutex variable and is no longer the owner of the mutex variable
Lock and Unlock concepts • If a thread tries to lock a mutex variable owned by another thread, then the thread that is not the owner is blocked until the mutex variable is unlocked • intpthread_mutex_lock(pthread_mutex_t *mutex) • intpthread_mutex_unlock(pthread_mutex_t *mutex) • intpthread_mutex_trylock(…) • Gets ownership of mutex if mutex is available, returns EBUSY if not available • Does not block/wait for lock. This thread can now do other work rather than waiting.
Mutex Variables • Two ways to initialize a mutex variable • mutex_var=PTHREAD_MUTEX_INITIALIZER • Can be used only with static variables for the default initial values • Can call the init function • intpthread_mutex_init(pthread_mutex_t *mutex_var, constpthread_mutexattr_t *attr) • Can be done on static or dynamic mutex variables • Can use NULL as the attr for default
Deadlocks with Mutexs • Thread 1 locks m1 then m2. Thread 2 locks m2 then m1. No unlocking happening between the locking. • If execution happens in the order t1 locks m1, t2 locks m2, then t1 waits for m2 while t2 waits for m1. • Can be avoided by having every thread use the same locking order. • Backing off – if cannot lock a mutex, unlock all the mutexs already locked and try again from the beginning.
Condition Variables • May need a certain condition to be true on a variable in a critical area before progressing • So the method would be • Get mutex –lock • Check value – if ok proceed • If not ok, release mutex and try again • Uses execution resources – busy wait loop. • Nicer if blocked and waiting so other processes could use the cpu • This is what Condition Variables (and operations) give us
Using Condition Variables • pthread_cond_tcond_var • intpthread_cond_init(pthread_cond_t *cond, constpthread_condattr_t * attr) • pthread_cond_tcond = PTHREAD_COND_INITIALIZER • A condition variable is used with a mutex variable.
Programming Condition Variables • First a mutex must be locked • intpthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t * mutex) • Typical code pattern: • pthread_mutex_lock (&mutex); • while (!condition() ) pthread_cond_wait(&cond, &mutex); • Do something • pthread_mutex_unlock(&mutex); • If condition is not true, the thread waits and the mutex is implicitly released. When another thread signals the condition, the waiting threads are unblocked. Hence the need for while (rather than if).
Condition Signal • intpthread_cond_signal(pthread_cond_t *cond); • Wakes up a single waiting thread (no effect if none waiting) • intpthread_cond_broadcast(pthread_cond_t*cond); • Wakes up all waiting threads
Topics • You can skip R/W _lock • Read about task pools • Read about pipelining • Read about client server • Read about producer consumer