240 likes | 404 Views
POSIX Threads. Nezer J. Zaidenberg. References. Advanced programming for the UNIX environment (2nd edition. This material does not exist in first edition) Further reading 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. This material does not exist in first edition) • Further reading • Yolinux.com : POSIX thread (pthread) libraries (very basic and I found some mistakes there!) • Programming with POSIX(R) Threads by David Botenhof (more advanced then this course) • http://www.ibm.com/developerworks/library/l-posix1.html (and chapters 2/3)
#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
Pthread_create 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 SYNOPSIS #include <pthread.h> void pthread_exit(void *retval); Arguments: * retval - Return value of thread.
Pthread join 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; pthread_attr_t pta; phread_parm_t *parm=NULL; printf("Create a thread attributes object¥n"); rc = pthread_attr_init(&pta); checkResults("pthread_attr_init()¥n", rc); parm = malloc(sizeof(thread_parm_t)); parm->value = 5; strcpy(parm->string, "Inside secondary thread"); rc = pthread_create(&thread, NULL, threadfunc, (void *)parm); parm = malloc(sizeof(thread_parm_t)); parm->value = 77; strcpy(parm->string, "Inside secondary thread");
Example 3/3 rc = pthread_create(&thread, &pta, threadfunc, (void *)parm); rc = pthread_attr_destroy(&pta); 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! • Avoid heap memory allocation. (It was used in the original example and I wanted to show shared memory and cases where one thread mallocs and another free.)
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),
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++; // was in orig example and evil :-) 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 Trylock 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]; pthread_attr_t attr; /* Initialize mutex and condition variable objects */ pthread_mutex_init(&count_mutex, NULL); pthread_cond_init (&count_threshold_cv, NULL); /* For portability, explicitly create threads in a joinable state */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
Cond 3/7 pthread_create(&threads[0], &attr, inc_count, (void *)&thread_ids[0]); pthread_create(&threads[1], &attr, inc_count, (void *)&thread_ids[1]); pthread_create(&threads[2], &attr, watch_count, (void *)&thread_ids[2]); /* 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_attr_destroy(&attr); 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++; // arrrrrrrggggghhhhh /* 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 < 1000; 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); }
Good and bad things • Don’t use x++ unless you have to • Check return code • In your practice code add some work so threads will alternate