1 #include int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void * (*start)(void *),...
Post on 22-Dec-2015
258 views
TRANSCRIPT
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);}