1 / 28

P-threads: create

P-threads: create. #include < pthread.h > int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void * (*start)(void *), void *args);. tid: space used to return the thread id attr: thread attributes -- NULL start: a pointer to a function that takes a single

kiley
Télécharger la présentation

P-threads: create

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. P-threads: create #include < pthread.h > int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void * (*start)(void *), void *args); • tid: space used to return the thread id • attr: thread attributes -- NULL • start: a pointer to a function that takes a single • argument of type void * and returns a value of type void * • args: a value to be passed as the argument to start • Return value: 0 means OK, non-zero indicates an error

  2. P-threads: join&detach #include < pthread.h > int pthread_join(pthread_t tid, void **status); int pthread_detach(pthread_t tid); • pthread_join: wait for thread tid to finish • status: will be set to point to the space where the return value from the start function will be stored • pthread_detach: thread cannot be joined. System will • reclaim resources on thread_exit.

  3. P-threads: example void *printme(void *){ printf("Hello world\n"); return NULL;} // could use pthread_exit(NULL) here main(){ pthread_t tid; void *status; if (pthread_create(&tid, NULL, printme, NULL) != 0) { perror("pthread_create”); exit(1); } if (pthread_join(tid, &status) != 0) { perror("pthread_join"); exit(1); } } Warning: tid is shared! What happens if you put a call to create in a loop?

  4. P-threads: multiple threads void *printme(void *arg) { int me = *((int *)arg); printf(“Hello from %d\n”, me); return NULL; } int main(){ int i, j, vals[4]; pthread_t tids[4]; void *retval; for (i = 0; i < 4; i++) { vals[i] = i; pthread_create(tids+i, NULL, printme, (void *)(vals+i)); } for (j = 0; j < 4; j++) { printf("Trying to join with tid %d\n", i); pthread_join(tids[j], (void **) &retval); printf("Joined with tid %d\n", j); } }

  5. P-threads: exit int main(){ int i, vals[4]; pthread_t tids[4]; for (i = 0; i < 4; i++) { vals[i] = i; pthread_create(tids+i, NULL, printme, (void *) (vals+i)); } return 0; } • Returning from astart function is equivalent to calling thread_exit • Returning from main is equivalent to calling exit!

  6. Pthreads: Servicing multiple clients struct harg { int newfd; struct sockaddr_in; }; void *handler(void *arg) { struct harg *harg = (struct harg *)arg; pthread_detach(pthread_self()); ... } int main() { pthread_t tid1; int sockfd = openServer(atoi(argv[1])); int addrsize = sizeof(struct sockaddr_in); while (1) { struct harg *arg = (struct harg *)malloc(sizeof(*arg)); arg->newfd = accept(sockfd, (struct sockaddr *) &arg->addr, &addrsize); pthread_t tid; pthread_create(&tid, NULL, handler, (void *)arg); } }

  7. P-threads: race condition example #define LEN 100 #define NUM_PARTS 4 #define PART_LEN LEN/NUM_PARTS void *sumPart(void *args) { int start = *((int *) args); int end = start + PART_LEN; int i; int mySum = 0; for (i = start; i <end; i++) { mySum += x[i]; } sum = sum + mySum; thread_exit(0); }

  8. P-threads: race condition example int main() { int i, *arg, rv; pthread_t tids[NUM_PARTS]; initialize(x, 1); // initialize x[0..SIZE-1] to 1 for (i = 0; i < NUM_PARTS; i++) { arg = (int *) malloc(sizeof(*arg)); *arg = i*PART_LEN; pthread_create(tids+i, NULL, sumPart, (void *)arg); } for (i = 0; i < NUM_PARTS; i++) { pthread_join(tids[i], (void **) &rv); } printf(“sum: %d\n”, sum); }

  9. P-threads:mutex locks pthread_mutex_t mutex_lock; pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t attr); pthread_mutex_lock(pthread_mutex_t *mutex); pthread_mutex_trylock(pthread_mutex_t *mutex); pthread_mutex_unlock(pthread_mutex_t *mutex); • pthread_mutex_init: initialize a mutex, use NULL for attrs. • pthread_mutex_lock: attempt to lock a mutex, will block if • the mutex is currently locked. • pthread_ mutex_trylock: attempt to lock a mutex, returns • with a busy error code if the lock is currently locked. • pthread_mutex_unlock: release a mutex. • returns an error (non-zero value) if the mutex • is not held by the calling thread

  10. P-threads: race condition example pthread_mutex_t sumLock; int main() { int i, *arg; pthread_t tids[4]; void *retval; initialize(x); pthread_mutex_init(&sumLock, NULL); for (i = 0; i < NUM_PARTS; i++) { arg = (int *) malloc(sizeof(*arg)); *arg = i*PART_LEN; pthread_create(tids+i, NULL, sumPart, (void *)arg); } for (i = 0; i < NUM_PARTS; i++) { pthread_join(tids[i], (void **)&retval); } pthread_mutex_destroy(&sumLock); printf(“sum: %d\n”, sum); }

  11. P-threads: race condition example void *sumPart(void *args) { int start = *((int) args); int end = start + PART_LEN; int i; int mySum = 0; for (i = start; i <end; i++) { mySum += x[i]; } mutex_lock(&sumLock); sum = sum + mySum; mutex_unlock(&sumLock); thread_exit(0); } Is there another way to solve this (particular) problem?

  12. P-threads: race condition example void *sumPart(void *args) { int start = ((int) args); int end = start + PART_LEN; int i; int mySum = 0; for (i = start; i <end; i++) { mySum += x[i]; } // reuse arg space for return value *((int *) args) = mySum; thread_exit((void *)args); }

  13. P-threads: race condition example int main() { int i,*arg; pthread_t tids[NUM_PARTS]; initialize(x, 1); // initialize x[0..SIZE-1] to 1 for (i = 0; i < NUM_PARTS; i++) { arg = (int *)malloc(sizeof(*arg)); *arg = i*PART_LEN; pthread_create(tids+i, NULL, sumPart, (void*)arg); } for (i = 0; i < NUM_PARTS; i++) { int *localSum; pthread_join(tids[i], (void **) &localSum); sum = sum + localSum; } printf(“sum: %d\n”, sum); }

  14. Pthreads: stack sharing example void *addOne(void *arg) { int *x = (int *) arg; *x = *x + 1; return NULL; } int main() { pthread_t tid1, tid2; int y = 7; void *rv; pthread_create(&tid1, NULL, addOne, (void *) &y); pthread_create(&tid2, NULL, addOne, (void *) &y); pthread_join(&tid1, (void **) &rv); pthread_join(&tid2, (void **) &rv); printf(“y: %d\n”, y); }

  15. Pthreads: functions with state void *useStatic(void *arg) { static int z = 0; z = z + 1; return (void *) &z; } int main() { pthread_t tid1, tid2; int *prv1, *prv2; pthread_create(&tid1, NULL, useStatic, NULL); pthread_create(&tid2, NULL, useStatic, NULL); pthread_join(tid1, (void **) &prv1); pthread_join(tid2, (void **) &prv2); printf(“rv1: %d\trv2: %d\n”, prv1, prv2); } • Real world example: gethostbyname

  16. Pthreads: lock and copy pthread_mutex_t zlock; void *useStatic(void *arg) { static int z = 0; z = z + 1; return (void *) &z; } void *safeUseStatic(void *arg) { int *rv = (int *) malloc(sizeof(int)); int *tmp; pthread_mutex_lock(&zlock); tmp = useStatic(arg); *rv = *tmp; pthread_mutex_unlock(&zlock); return rv; } int main() { pthread_mutex_init(&zlock, NULL); // create threads to call safeUseStatic... }

  17. Pthreads: functions with state int z; void initZ(int x) { z = x; } void *useGlobal(void *arg) { z = z + 1; return (void *)z; } int main() { pthread_t tid1, tid2; int rv1, rv2; initZ(7); /* create threads ... */ pthread_join(tid1, (void **) &rv1); pthread_join(tid2, (void **) &rv1); printf(“rv1: %d\trv2: %d\n”, rv1, rv2); } • Real world example: rand

  18. Pthreads: state arguments void *useState(void *arg) { int z = *(int *)arg; z = z + 1; *arg = z; return (void *)z; } int main() { pthread_t tid1, tid2; int rv1, rv2; int z1 = 7, z2 = 7; // initialize the state pthread_create(&tid1, NULL, useGlobal, (void *)&z1); pthread_create(&tid1, NULL, useGlobal, (void *)&z2); pthread_join(&tid1, (void *) &rv1); pthread_join(&tid2, (void *) &rv2); printf(“rv1: %d\trv2: %d\n”, rv1, rv2); } • Real world example: rand_r

  19. PThreads: Deadlock pthread_mutex_t A, B; void *lockAB(void *arg) { pthread_mutex_lock(&A); pthread_mutex_lock(&B); ....do work... pthread_mutex_unlock(&B); pthread_mutex_unlock(&A); } void *lockBA(void *arg) { pthread_mutex_lock(&B); pthread_mutex_lock(&A); ....do other work... pthread_mutex_unlock(&A); pthread_mutex_unlock(&B); }

  20. Pthreads: Deadlock continued int main() { pthread_t tid1, tid; pthread_mutex_init(&A, NULL); pthread_mutex_init(&B, NULL); pthread_create(&tid1, NULL, lockAB, NULL); pthread_create(&tid2, NULL, lockBA, NULL); pthread_exit(0); } Solution: (1) define an ordering on the locks (2) acquire locks in order (3) release locks in reverse order

  21. PThreads: Semaphores #include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); int sem_wait(sem_t *sem); int sem_post(sem_t *sem); int sem_destroy(sem_t *sem); sem_init: initialize a semaphore. • pshared should be zero. • value is the initial value for the semaphore sem_wait: wait for the value to be > 0, then decrement and then continue sem_post: increment semaphore (will wake up a waiting thread) sem_destroy: free the semaphore

  22. Pthreads: Semaphore example struct job { struct job *next; // other fields related to the job } *queue; pthread_mutex_t q_lock; sem_t q_cnt; void initJQ() { pthread_mutex_init(&q_lock, NULL); sem_init(&q_cnt, 0, 0); queue = NULL; }

  23. Pthreads: Semaphore example void process_jobs(void *arg) { while (1) { sem_wait(&q_cnt); pthread_mutex_lock(&q_lock); ... take job off queue ... pthread_mutex_unlock(&q_lock); ... process job ... } }

  24. Pthreads: Semaphore example void enqueue_job() { pthread_mutex_lock(&queue); ... add job to the queue ... sem_post(&q_cnt); pthread_mutex_unlock(&queue); }

  25. Condition variables: my turn example -- dumb int myTurn = 0; int numThreads = 4; pthread_mutex_t lock; void *myTurnFn(void *args) { int myID = *((int *)args); while (1) { pthread_mutex_lock(lock); /* get lock */ while((myTurn % numThreads) != myID) { pthread_mutex_unlock(lock); /* give it up! */ pthread_mutex_lock(t->lock); /* get it again */ } /* do some work */ pthread_mutex_unlock(lock); /* give it up! */ } }

  26. Pthreads:condition variables A thread t: (1) grabs a lock (2a) tests to see if a condition holds, if so t proceeds (3a) signals when done. (2b) if not, goes to sleep, implicitly releasing the lock, (3b) re-awakes holding the lock when signaled by another thread. int pthread_cond_init(pthread_cond_t *cond, pthread_cond_attr_t *cond_attr); int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond);

  27. Pthreads:my turn w/ CV int myTurn = 0; int numThreads = 4; pthread_mutex_t lock; // initialize to unlocked pthread_cond_t cv; // initialize to unavailable void *myTurnFn(void *args) { int myID = *((int *)args); while (1) { pthread_mutex_lock(&lock); while((myTurn % numThreads) != myID) { pthread_cond_wait(&cv, &lock); } /* do some work */ pthread_cond_broadcast(&cv); pthread_mutex_unlock(&lock);/*order matters! */ } }

  28. typedef struct { pthread_mutex_t *lock; pthread_cond_t *cv; int *ndone; int nthreads; int id; } TStruct; void *barrier(void *arg) { TStruct *ts = (TStruct *)arg; int i; printf("Thread %d -- waiting for barrier\n", ts->id); pthread_mutex_lock(ts->lock); *ts->ndone = *ts->ndone + 1; if (*ts->ndone < ts->nthreads) pthread_cond_wait(ts->cv, ts->lock); else for (i = 1; i < NTHREADS; i++) pthread_cond_signal(ts->cv); pthread_mutex_unlock(ts->lock); printf("Thread %d -- after barrier\n", ts->id); }

More Related