28
1 #include < pthread.h > int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void * (*start)(void *), void *args); P-threads: create 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

1 #include int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void * (*start)(void *), void *args); P-threads: create tid: space used to return

  • View
    241

  • Download
    0

Embed Size (px)

Citation preview

1

#include < pthread.h >

int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void * (*start)(void *), void *args);

P-threads: create

•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

#include < pthread.h >

int pthread_join(pthread_t tid, void **status);

int pthread_detach(pthread_t tid);

P-threads: join&detach

•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 willreclaim resources on thread_exit.

3

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); }}

P-threads: example

Warning: tid is shared! What happens if you put a call to create in a loop?

4

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); }}

P-threads: multiple threads

5

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;}

P-threads: exit

•Returning from a start function is equivalent to calling thread_exit•Returning from main is equivalent to calling exit!

6

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); }}

Pthreads: Servicing multiple clients

7

#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);}

P-threads: race condition example

8

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);}

P-threads: race condition example

9

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);

P-threads:mutex locks

•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 mutexis not held by the calling thread

10

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);}

P-threads: race condition example

11

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);}

P-threads: race condition example

Is there another way to solve this (particular) problem?

12

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);}

P-threads: race condition example

13

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);}

P-threads: race condition example

14

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); }

Pthreads: stack sharing example

15

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);}

Pthreads: functions with state

•Real world example: gethostbyname

16

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...}

Pthreads: lock and copy

17

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);}

Pthreads: functions with state

•Real world example: rand

18

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);}

Pthreads: state arguments

•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

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! */ } }

Condition variables: my turn example -- dumb

26

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);

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.

27

int myTurn = 0;int numThreads = 4;pthread_mutex_t lock; // initialize to unlockedpthread_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! */ } }

Pthreads:my turn w/ CV

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);}