POSIX Threads In the UNIX environment a thread: • Exists within a process and uses the process POSIX Threads resources. • Has its own independent flow of control as long as its parent process exists or the OS supports it. HUJI • May share the process resources with other Spring 2007 threads that act equally independently (and dependently). • Dies if the parent process dies (user thread). 1 2 Pthread Attributes Why Threads • Managing threads requires fewer system A thread can possess an independent flow of resources than managing processes. control and be schedulable because it – fork() Versus pthread_create() maintains its own: • All threads within a process share the same address space . – Stack. – Registers. (CPU STATE!) – Inter-thread communication is more efficient and easier to use than inter-process communication – Scheduling properties (such as policy or priority). (IPC). – Set of pending and blocked signals. • Overlapping CPU work with I/O. – Thread specific data. • Priority/real-time scheduling. • Asynchronous event handling. 3 4 Pthread Library Creating Threads The subroutines which comprise the Pthreads • Initially, your main() program comprises a API can be informally grouped into 3 major classes: single, default thread. All other threads must – Thread management: The first class of functions be explicitly created by the programmer. work directly on threads. – Mutexes: The second class of functions deals int pthread_create ( with synchronization, called a "mutual exclusion". pthread_t *thread, – Condition variables: The third class of functions addresses communications between threads that const pthread_attr_t *attr=NULL, share a mutex. void *(*start_routine) (void *), void *arg) ; How to Compile? #include <pthread.h> gcc ex3.c –o ex3 –lpthread 5 6 1
#define NUM_THREADS 5 void *PrintHello(void *index) { printf("\n%d: Hello World!\n", index); Terminating Thread Execution pthread_exit(NULL); } int main(int argc, char *argv[]) { • The thread returns from its starting pthread_t threads[NUM_THREADS]; int res, t; routine (the main routine for the initial for(t=0;t<NUM_THREADS;t++){ thread). printf("Creating thread %d\n", t); res = pthread_create(&threads[t], NULL, • The thread makes a call to the PrintHello, (void *)t); pthread_exit(status) subroutine. if (res){ printf("ERROR\n"); • The entire process is terminated due to exit(-1); } a call to either the exec or exit } subroutines. pthread_exit(NULL); } 7 8 Joining Threads Example Cont. int pthread_join(pthread_t thread, // main thread waits for the other threads void **value_ptr); for(t=0;t<NUM_THREADS;t++) { res = pthread_join(threads[t], (void **)&status); if (res) { printf("ERROR \n"); • The pthread_join() subroutine blocks the exit(-1); calling thread until the specified thread thread } printf("Completed join with thread %d status= terminates. %d\n",t, status); • The programmer is able to obtain the target } pthread_exit(NULL); thread's termination return status if specified } through pthread_exit(void *status). 9 10 Example 1 - pthread_join void *printme(void *ip) { int *i; i = (int *) ip; printf("Hi. I'm thread %d\n", *i); return NULL; } main() { Few Examples int i, vals[4]; pthread_t tids[4]; void *retval; for (i = 0; i < 4; i++) { vals[i] = i; pthread_create(tids+i, NULL, printme, vals+i); } for (i = 0; i < 4; i++) { printf("Trying to join with tid %d\n", i); pthread_join(tids[i], &retval); printf("Joined with tid %d\n", i); } 11 12 } 2
Example 2 - pthread_exit void *printme(void *ip) { Output int *i; i = (int *) ip; printf("Hi. I'm thread %d\n", *i); Trying to join with tid 0 pthread_exit(NULL); Hi. I'm thread 0 } main() { Hi. I'm thread 1 int i, vals[4]; Hi. I'm thread 2 pthread_t tids[4]; Hi. I'm thread 3 void *retval; for (i = 0; i < 4; i++) { Joined with tid 0 vals[i] = i; Trying to join with tid 1 pthread_create(tids+i, NULL, printme, vals+i); } Joined with tid 1 pthread_exit(NULL); Trying to join with tid 2 for (i = 0; i < 4; i++) { Joined with tid 2 printf("Trying to join with tid %d\n", i); pthread_join(tids[i], &retval); Trying to join with tid 3 printf("Joined with tid %d\n", i); Joined with tid 3 } 13 14 } Example 3 - Exit void *printme(void *ip) { The Output int *i; i = (int *) ip; printf("Hi. I'm thread %d\n", *i); Hi. I'm thread 0 exit(0); } Hi. I'm thread 1 main() { int i, vals[4]; Hi. I'm thread 2 pthread_t tids[4]; void *retval; Hi. I'm thread 3 for (i = 0; i < 4; i++) { vals[i] = i; pthread_create(tids+i, NULL, printme, vals+i); } for (i = 0; i < 4; i++) { printf("Trying to join with tid %d\n", i); pthread_join(tids[i], &retval); printf("Joined with tid %d\n", i); } 15 16 } Output? Trying to join with tid 0 Hi. I'm thread 0 Pthread Synchronization 17 18 3
Mutex Critical Section • Mutex variables are one of the primary 1 st thread 2 nd thread Balance means of implementing thread synchronization and for protecting shared 1000$ Read balance: data when multiple writes occur. 1000$ • A mutex variable acts like a "lock" protecting 1000$ Read balance: 1000$ access to a shared data resource. 1000$ Deposit: 200$ • The basic concept of a mutex as used in Pthreads is that only one thread can lock (or 1000$ Deposit: 200$ own) a mutex variable at any given time . 1200$ Update balance 1200$ Update balance 19 20 Creating and Destroying Mutex Work Flow Mutex variables must be declared with type A typical sequence in the use of a mutex is as pthread_mutex_t , and must be initialized before follows: they can be used: • Create and initialize a mutex variable. – Statically, when it is declared. For example: • Several threads attempt to lock the mutex. pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER ; • Only one succeeds and that thread owns the – Dynamically, mutex. pthread_mutex_init(mutex, attr) • The owner thread performs some set of actions. This method permits setting mutex object attributes (for • The owner unlocks the mutex. default setting use NULL). • Another thread acquires the mutex and repeats pthread_mutex_destroy(mutex) should be the process. used to free a mutex object when is no longer needed. • Finally the mutex is destroyed. 21 22 Locking Mutex Unlock Mutex • The pthread_mutex_lock(mutex) • pthread_mutex_unlock(mutex) routine is used by a thread to acquire a will unlock a mutex if called by the lock on the specified mutex variable. owning thread. Calling this routine is • If the mutex is already locked by required after a thread has completed its use of protected data. another thread, this call will block the calling thread until the mutex is • An error will be returned if: unlocked. – If the mutex was already unlocked. – If the mutex is owned by another thread. 23 24 4
Fixed Example Example pthread_mutex_lock (&mut); Thread 2: Thread 1: a = counter; a++; a = counter; counter = a; b = counter; pthread_mutex_unlock (&mut); a++; pthread_mutex_lock (&mut); b--; b = counter ; counter = a; b--; counter = b; counter = b; pthread_mutex_unlock (&mut); 25 26 Conditional Variables Condition Variables • While mutexes implement synchronization by • Useful when a thread needs to wait for a controlling thread access to data, condition certain condition to be true. variables allow threads to synchronize based • In pthreads , there are four relevant procedures involving condition variables : upon the actual value of data. – pthread_cond_init(pthread_cond_t *cv, • Without condition variables, The programmer NULL); would need to have threads continually polling – pthread_cond_destroy(pthread_cond_t *cv); (usually in a critical section), to check if the – pthread_cond_wait(pthread_cond_t *cv, condition is met. pthread_mutex_t *lock); • A condition variable is a way to achieve the same – pthread_cond_signal(pthread_cond_t *cv); goal without polling (a.k.a. busy wait) 27 28 Creating and Destroying pthread_cond_wait Conditional Variables • Condition variables must be declared with type • pthread_cond_wait(cv, lock) is called pthread_cond_t , and must be initialized by a thread when it wants to block and wait before they can be used. for a condition to be true. • Statically, when it is declared. For example: • It is assumed that the thread has locked the pthread_cond_t myconvar = mutex indicated by the second parameter. PTHREAD_COND_INITIALIZER; • The thread releases the mutex, and blocks • Dynamically until awakened by a pthread_cond_signal() call from another pthread_cond_init(cond, attr); thread. Upon successful initialization, the state of the condition variable becomes initialized. • When it is awakened, it waits until it can acquire the mutex, and once acquired, it • pthread_cond_destroy(cond) should be returns from the pthread_cond_wait() used to free a condition variable that is no call. longer needed. 29 30 5
Recommend
More recommend