Beruflich Dokumente
Kultur Dokumente
1 2
1
#define NUM_THREADS 5
7 8
Example 1 - pthread_join
void *printme(void *ip) {
int *i;
i = (int *) ip;
printf("Hi. I'm thread %d\n", *i);
return NULL;
}
main() {
Few Examples int i, vals[4];
pthread_t tids[4];
void *retval;
for (i = 0; i < 4; i++) {
vals[i] = i;
pthread_create(tids+i, NULL, printme, vals+i);
}
for (i = 0; i < 4; i++) {
printf("Trying to join with tid %d\n", i);
pthread_join(tids[i], &retval);
printf("Joined with tid %d\n", i);
11 } 12
}
2
Example 2 - pthread_exit
void *printme(void *ip) {
Example 3 - Exit
void *printme(void *ip) {
The Output int *i;
i = (int *) ip;
printf("Hi. I'm thread %d\n", *i);
Hi. I'm thread 0 }
exit(0);
Output?
Trying to join with tid 0
Hi. I'm thread 0 Pthread Synchronization
17 18
3
Mutex
Critical Section
• Mutex variables are one of the primary
Balance 1st thread 2nd thread means of implementing thread
1000$ Read balance: synchronization and for protecting shared
1000$ data when multiple writes occur.
1000$ Read balance: • A mutex variable acts like a "lock" protecting
1000$ access to a shared data resource.
1000$ Deposit: 200$ • The basic concept of a mutex as used in
1000$ Deposit: 200$ Pthreads is that only one thread can lock (or
own) a mutex variable at any given time.
1200$ Update balance
1200$ Update balance 19 20
23 24
4
Example Fixed Example
pthread_mutex_lock (&mut);
Thread 1: Thread 2: a = counter;
a++;
a = counter;
counter = a;
b = counter; pthread_mutex_unlock (&mut);
a++;
pthread_mutex_lock (&mut);
b--; b = counter;
counter = a; b--;
counter = b; counter = b;
pthread_mutex_unlock (&mut);
25 26
Conditional Variables
Condition Variables
• While mutexes implement synchronization by • Useful when a thread needs to wait for a
controlling thread access to data, condition certain condition to be true.
variables allow threads to synchronize based • In pthreads, there are four relevant
upon the actual value of data. procedures involving condition variables:
– pthread_cond_init(pthread_cond_t *cv,
• Without condition variables, The programmer NULL);
would need to have threads continually polling – pthread_cond_destroy(pthread_cond_t
(usually in a critical section), to check if the *cv);
– pthread_cond_wait(pthread_cond_t *cv,
condition is met. pthread_mutex_t *lock);
• A condition variable is a way to achieve the same – pthread_cond_signal(pthread_cond_t
*cv);
goal without polling (a.k.a. busy wait)
27 28
5
typedef struct {
pthread_cond_signal pthread_mutex_t *lock;
pthread_cond_t *cv;
• pthread_cond_signal() checks to see if int *ndone;
int id;
there are any threads waiting on the specified } TStruct;
condition variable. If not, then it simply returns. #define NTHREADS 5
void *barrier(void *arg) {
• If there are threads waiting, then one is TStruct *ts;
awakened. int i;
ts = (TStruct *) arg;
• There can be no assumption about the order in printf("Thread %d -- waiting for barrier\n", ts->id);
pthread_mutex_lock(ts->lock);
which threads are awakened by *ts->ndone = *ts->ndone + 1;
pthread_cond_signal() calls. if (*ts->ndone < NTHREADS) {
pthread_cond_wait(ts->cv, ts->lock);
• It is natural to assume that they will be }
awakened in the order in which they waited, but else {
that may not be the case… for (i = 1; i < NTHREADS; i++)
pthread_cond_signal(ts->cv);
• Use loop or pthread_cond_broadcast() to }
pthread_mutex_unlock(ts->lock);
awake all waiting threads. printf("Thread %d -- after barrier\n", ts->id);
31 32
}
main() {
TStruct ts[NTHREADS];
pthread_t tids[NTHREADS];
int i, ndone;
Output
pthread_mutex_t lock; Thread 0 -- waiting for barrier
pthread_cond_t cv;
void *retval; Thread 1 -- waiting for barrier
pthread_mutex_init(&lock, NULL); Thread 2 -- waiting for barrier
pthread_cond_init(&cv, NULL);
ndone = 0;
Thread 3 -- waiting for barrier
for (i = 0; i < NTHREADS; i++) { Thread 4 -- waiting for barrier
ts[i].lock = &lock; Thread 4 -- after barrier
ts[i].cv = &cv;
ts[i].ndone = &ndone; Thread 0 -- after barrier
ts[i].id = i; Thread 1 -- after barrier
}
for (i = 0; i < NTHREADS; i++)
Thread 2 -- after barrier
pthread_create(tids+i, NULL, barrier, ts+i); Thread 3 -- after barrier
for (i = 0; i < NTHREADS; i++) done
pthread_join(tids[i], &retval); 33 34
printf("done\n"); }
35 36
6
Bounded-Buffer Problem – Bounded-Buffer Problem –
Cont. Cont.
• The structure of the producer process • The structure of the consumer process
Readers-Writers Problem
Readers-Writers Problem – Cont.
• A data set is shared among a number of concurrent processes
– Readers – only read the data set; they do not perform any updates • The structure of a writer process
– Writers – can both read and write.
7
Writer-Priority: The Reader
while (true) { Queue semaphore, initialized to 1:
Dining-Philosophers Problem
P(queue) Since ‘read’ can not be a queue
P(read) (otherwise, writer won’t skip
multiple readers), we have to
P (rmutex) ;
maintain another semaphore
readcount ++ ;
if (readcount == 1) P (wrt) ;
V (rmutex)
V(read)
V(queue)
// reading is performed
P (rmutex) ;
readcount - - ;
if (readcount == 0) V (wrt) ; Shared data
V (rmutex) ; Bowl of rice (data set)
}
43 Semaphore chopstick [5] initialized to 1 44