Title: Pthreads: create
1P-threads create
include lt pthread.h gt 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
2P-threads joindetach
include lt pthread.h gt 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.
3P-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?
4P-threads multiple threads
void printme(void arg) int me ((int
)arg) printf(Hello from d\n, me) return
NULL int main() int i, j, vals4
pthread_t tids4 void retval for (i 0
i lt 4 i) valsi i
pthread_create(tidsi, NULL, printme, (void
)(valsi)) for (j 0 j lt 4 j)
printf("Trying to join with tid d\n", i)
pthread_join(tidsj, (void ) retval)
printf("Joined with tid d\n", j)
5P-threads exit
int main() int i, vals4 pthread_t
tids4 for (i 0 i lt 4 i)
valsi i pthread_create(tidsi, NULL,
printme, (void ) (valsi)) return 0
- Returning from a start function is equivalent to
calling thread_exit - Returning from main is equivalent to calling exit!
6Pthreads 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(argv1)) int addrsize
sizeof(struct sockaddr_in) while (1)
struct harg arg (struct harg
)malloc(sizeof(arg)) arg-gtnewfd
accept(sockfd, (struct sockaddr )
arg-gtaddr, addrsize) pthread_t
tid pthread_create(tid, NULL, handler, (void
)arg)
7P-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 ltend i) mySum xi
sum sum mySum thread_exit(0)
8P-threads race condition example
int main() int i, arg, rv pthread_t
tidsNUM_PARTS initialize(x, 1) //
initialize x0..SIZE-1 to 1 for (i 0 i lt
NUM_PARTS i) arg (int )
malloc(sizeof(arg)) arg
iPART_LEN pthread_create(tidsi, NULL,
sumPart, (void )arg) for (i 0 i lt
NUM_PARTS i) pthread_join(tidsi, (void
) rv) printf(sum d\n, sum)
9P-threadsmutex locks
pthread_mutex_t mutex_lock pthread_mutex_init(pt
hread_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
10P-threads race condition example
pthread_mutex_t sumLock int main() int i,
arg pthread_t tids4 void retval
initialize(x) pthread_mutex_init(sumLock,
NULL) for (i 0 i lt NUM_PARTS i)
arg (int ) malloc(sizeof(arg)) arg
iPART_LEN pthread_create(tidsi, NULL,
sumPart, (void )arg) for (i 0 i lt
NUM_PARTS i) pthread_join(tidsi, (void
)retval) pthread_mutex_destroy(sumLock
) printf(sum d\n, sum)
11P-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 ltend i)
mySum xi mutex_lock(sumLock)
sum sum mySum mutex_unlock(sumLock)
thread_exit(0)
Is there another way to solve this (particular)
problem?
12P-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 ltend i)
mySum xi // reuse arg space
for return value ((int ) args) mySum
thread_exit((void )args)
13P-threads race condition example
int main() int i,arg pthread_t
tidsNUM_PARTS initialize(x, 1) //
initialize x0..SIZE-1 to 1 for (i 0 i lt
NUM_PARTS i) arg (int
)malloc(sizeof(arg)) arg
iPART_LEN pthread_create(tidsi, NULL,
sumPart, (void)arg) for (i 0 i lt
NUM_PARTS i) int localSum
pthread_join(tidsi, (void ) localSum)
sum sum localSum printf(sum d\n,
sum)
14Pthreads 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)
15Pthreads 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
16Pthreads 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...
17Pthreads 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)
18Pthreads 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
19PThreads 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)
-
20Pthreads 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
21PThreads Semaphores
- include ltsemaphore.hgt
- 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 gt 0, then decrement and
then continue
sem_post increment semaphore (will wake up a
waiting thread)
sem_destroy free the semaphore
22Pthreads 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
23Pthreads 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 ...
-
-
24Pthreads Semaphore example
- void enqueue_job()
- pthread_mutex_lock(queue)
- ... add job to the queue ...
- sem_post(q_cnt)
- pthread_mutex_unlock(queue)
-
25Condition 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-gtlock)
/ get it again / / do some
work / pthread_mutex_unlock(lock) / give
it up! /
26Pthreadscondition 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)
27Pthreadsmy 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-gtid) - pthread_mutex_lock(ts-gtlock)
-
- ts-gtndone ts-gtndone 1
- if (ts-gtndone lt ts-gtnthreads)
- pthread_cond_wait(ts-gtcv, ts-gtlock)