290 likes | 558 Views
POSIX Threads. Nezer J. Zaidenberg. References. Advanced programming for the UNIX environment (2nd edition chapter 11+12 This material does not exist in first edition) Many manuals exist on the web Yolinux.com : POSIX thread (pthread) libraries (very basic and I found some mistakes there!)
E N D
POSIX Threads Nezer J. Zaidenberg
References • Advanced programming for the UNIX environment (2nd edition chapter 11+12 This material does not exist in first edition) • Many manuals exist on the web • Yolinux.com : POSIX thread (pthread) libraries (very basic and I found some mistakes there!) • http://www.ibm.com/developerworks/library/l-posix1.html (and chapters 2/3) • Programming with POSIX(R) Threads by David Botenhof (more advanced then this course)
#include <stdio.h> #include <stdlib.h> #include <pthread.h> void *print_message_function( void *ptr ); main() { pthread_t thread1, thread2; char *message1 = "Thread 1"; char *message2 = "Thread 2"; pthread_create( &thread1, NULL, print_message_function, (void*) message1); pthread_create( &thread2, NULL, print_message_function, (void*) message2); pthread_join( thread1, NULL); pthread_join( thread2, NULL); exit(0); } void *print_message_function( void *ptr ) { char *message; message = (char *) ptr; printf("%s \n", message); }
Two important notes • To compile : • C : gcc -lpthread thread.c • C++ : g++ -lpthread thread.cxx • Other platforms and compilers may require -pthread flag instead • Never code like this • You should check pthread create return value
Why do we need thread library • In Linux malloc(3) is normally not thread safe to speed things up (no locking and unlocking) • That means that when we use threads – we must use different malloc(3) • This is also true in Windows while in OSX malloc is always thread safe.
Pthread_create(3) SYNOPSIS #include <pthread.h> int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void * (*start_routine)(void *), void *arg); Arguments thread - returns the thread id. (unsigned long int defined in bits/pthreadtypes.h) attr - Set to NULL if default thread attributes are used. (else define members of the struct pthread_attr_t defined in bits/pthreadtypes.h) void * (*start_routine) - pointer to the function to be threaded. Function has a single argument: pointer to void. *arg - pointer to argument of function. To pass multiple arguments, send a pointer to a structure.
Pthread exit(3) – exit(2) for threads SYNOPSIS #include <pthread.h> void pthread_exit(void *retval); Arguments: * retval - Return value of thread.
Pthread join(3) – wait(2) for threads SYNOPSIS #include <pthread.h> int pthread_join(pthread_t thread, void **value_ptr); Arguments Value_ptr = the value returned by thread This function is BLOCKING!!!
Passing arguments to/from threads • Can be done using the void pointer (cast the void * into a struct and point into any number of arguments) • Return values can be returned in the same way • Shared memory is also used for this (but is less recommended because of problems with syncing)
Example (1/3) #define _MULTI_THREADED #include <pthread.h> #include <stdio.h> #include "check.h” typedef struct { int value; char string[128]; } thread_parm_t; void *threadfunc(void *parm) { thread_parm_t *p = (thread_parm_t *)parm; printf("%s, parm = %d\n", p->string, p->value); free(p); return NULL; }
Example 2/3 int main(int argc, char **argv) { pthread_t thread; int rc=0; thread_parm_t *parm=NULL; printf("Create a thread attributes object\n"); parm = malloc(sizeof(thread_parm_t)); parm->value = 5; strcpy(parm->string, "Inside first thread"); rc = pthread_create(&thread, NULL, threadfunc, (void *)parm); parm = malloc(sizeof(thread_parm_t)); parm->value = 77; strcpy(parm->string, "Inside second thread");
Example 3/3 rc = pthread_create(&thread, NULL, threadfunc, (void *)parm); sleep(5); printf("Main completed\n"); return 0; }
Problems with example • Check return code (existed in the original example) • Don’t use sleep() to wait for thread! – use pthread_join(3). • Avoid heap memory allocation. (It was used in the original example and I wanted to show shared memory and cases where one thread malloc(3)s and another free(3).)
Thread attributes • detached state (joinable? Default: PTHREAD_CREATE_JOINABLE. Other option: PTHREAD_CREATE_DETACHED) • scheduling policy (real-time? PTHREAD_INHERIT_SCHED,PTHREAD_EXPLICIT_SCHED,SCHED_OTHER) • scheduling parameter • inheritsched attribute (Default: PTHREAD_EXPLICIT_SCHED Inherit from parent thread: PTHREAD_INHERIT_SCHED) • scope (Kernel threads: PTHREAD_SCOPE_SYSTEM User threads: PTHREAD_SCOPE_PROCESS Pick one or the other not both.) • guard size • stack address (See unistd.h and bits/posix_opt.h _POSIX_THREAD_ATTR_STACKADDR) • stack size (default minimum PTHREAD_STACK_SIZE set in pthread.h),
In the scope of this course we will always use NULL for thread attributes
Sync using mutex (1/2) #include <stdio.h> #include <stdlib.h> #include <pthread.h> pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; int counter = 0; void *functionC() { pthread_mutex_lock( &mutex1 ); counter++; printf("Counter value: %d\n",counter); pthread_mutex_unlock( &mutex1 ); }
Syncing 2/2 int main() { int rc1, rc2; pthread_t thread1, thread2; if( (rc1=pthread_create( &thread1, NULL, &functionC, NULL)) ) { printf("Thread creation failed: %d\n", rc1); } if( (rc2=pthread_create( &thread2, NULL, &functionC, NULL)) ) { printf("Thread creation failed: %d\n", rc2); } // ++counter pthread_join( thread1, NULL); pthread_join( thread2, NULL); exit(0); }
Pthread_mutex_lock SYNOPSIS #include <pthread.h> int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); Lock function is blocking Try lock function is not blocking (it would lock if it can) Unlock release
Using cond (1/7) #include <pthread.h> #include <stdio.h> #include <stdlib.h> #define NUM_THREADS 3 #define TCOUNT 10 #define COUNT_LIMIT 12 int count = 0; int thread_ids[3] = {0,1,2}; pthread_mutex_t count_mutex; pthread_cond_t count_threshold_cv;
Using cond 2/7 int main(int argc, char *argv[]) { int i, rc; pthread_t threads[3]; /* Initialize mutex and condition variable objects */ pthread_mutex_init(&count_mutex, NULL); pthread_cond_init (&count_threshold_cv, NULL); pthread_create(&threads[0], NULL, inc_count, (void *)&thread_ids[0]); pthread_create(&threads[1], NULL, inc_count, (void *)&thread_ids[1]); pthread_create(&threads[2], NULL, watch_count, (void *)&thread_ids[2]);
Cond 3/7 /* Wait for all threads to complete */ for (i = 0; i < NUM_THREADS; i++) { pthread_join(threads[i], NULL); } printf ("Main(): Waited on %d threads. Done.\n", NUM_THREADS); /* Clean up and exit */ pthread_mutex_destroy(&count_mutex); pthread_cond_destroy(&count_threshold_cv); pthread_exit (NULL); }
Using cond 4/7 void *inc_count(void *idp) { int j,i; double result=0.0; int *my_id = idp; for (i=0; i < TCOUNT; i++) { pthread_mutex_lock(&count_mutex); count++; /* Check the value of count and signal waiting thread when condition is reached. Note that this occurs while mutex is locked. */
Cond 5/7 if (count == COUNT_LIMIT) { pthread_cond_signal(&count_threshold_cv); printf("inc_count(): thread %d, count = %d Threshold reached.\n", *my_id, count); } printf("inc_count(): thread %d, count = %d, unlocking mutex\n”, *my_id, count); pthread_mutex_unlock(&count_mutex); /* Do some work so threads can alternate on mutex lock */ for (j=0; j < 10000; j++) result = result + (double)random(); } pthread_exit(NULL); }
Using cond 6/7 void *watch_count(void *idp) { int *my_id = idp; printf("Starting watch_count(): thread %d\n", *my_id); /* Lock mutex and wait for signal. Note that the pthread_cond_wait routine will automatically and atomically unlock mutex while it waits. Also, note that if COUNT_LIMIT is reached before this routine is run by the waiting thread, the loop will be skipped to prevent pthread_cond_wait from never returning. */
Using Cond 7/7 pthread_mutex_lock(&count_mutex); if (count < COUNT_LIMIT) { pthread_cond_wait(&count_threshold_cv, &count_mutex); printf("watch_count(): thread %d Condition signal received.\n", *my_id); } pthread_mutex_unlock(&count_mutex); pthread_exit(NULL); }
Things to note • Cond modify a mutex. • Cond operations are protected by mutex.
Good and bad things • Check return code • In your practice code add some work so threads will alternate