Race Condition Shared Data: 4 5 6 1 8 5 6 20 9 ? Synchronization and Deadlocks tail A[] (or The Dangers of Threading) Enqueue(): A[tail] = 20; A[tail] = 9; Jonathan Misurda tail++; tail++; thread jmisurda@cs.pitt.edu switch Thread 0 Thread 1 Critical Regions Synchronization • Scheduling can be random and preemption can happen at any time Enters Leaves critical region critical region • Need some way to make critical regions Thread 0 Leaves “atomic” Enters Tries to enter critical region critical region critical region Thread 1 B blocked • Need help from the Operating System Time Mutex Critical Sections Shared Data: • MUTual EXclusion 4 tail 5 6 1 8 5 6 20 9 • A mutex is a lock that only one thread can A[] mutex acquire • All other threads attempting to enter the Blocked! Enqueue(): critical region will be blocked lock(&mutex); lock(&mutex); A[tail] = 20; A[tail] = 9; thread switch tail++; tail++; unlock(&mutex); unlock(&mutex); Thread 0 Thread 1
pthread_mutex_t Producer/Consumer Problem Shared variables #include <stdio.h> #define N 10; #include <pthread.h> int buffer[N]; int in = 0, out = 0, counter = 0; int tail = 0; Producer Consumer int A[20]; while (1) { while (1) { pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; if (counter == N) if (counter == 0) sleep(); sleep(); void enqueue(int value) buffer[in] = ... ; ... = buffer[out]; { in = (in+1) % N; out = (out+1) % N; pthread_mutex_lock(&mutex); counter++; counter ‐‐ ; A[tail] = value; tail++; if (counter==1) if (count == N ‐ 1) pthread_mutex_unlock(&mutex); wakeup(consumer); wakeup(producer); } } } Deadlocks Condition Variables • “A set of processes is deadlocked if each • A condition under which a thread executes or process in the set is waiting for an event that is blocked only another process in the set can cause.” • pthread_cond_t • Caused when: 1. Mutual exclusion • pthread_cond_wait (condition, mutex) 2. Hold and wait • pthread_cond_signal (condition) 3. No preemption of resource 4. Circular wait Producer/Consumer Semaphores #define N 10 int buffer[N]; int counter = 0, in = 0, out = 0, total = 0; • A lock that remembers “missed” wakeups pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t prod_cond = PTHREAD_COND_INITIALIZER; pthread_cond_t cons_cond = PTHREAD_COND_INITIALIZER; • Mutexes are a special case of Semaphores void *producer(void *junk) { void *consumer(void *junk) { while(1) { while(1) { that only count to 1 pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex); if( counter == N ) pthread_cond_wait(&prod_cond, if( counter == 0 ) &mutex); pthread_cond_wait(&cons_cond, &mutex); buffer[in] = total++; printf("Produced: %d\n", printf("Consumed: %d\n", buffer[in]); buffer[out]); in = (in + 1) % N; out = (out + 1) % N; counter++; counter ‐‐ ; if( counter == 1 ) if( counter == (N ‐ 1) ) pthread_cond_signal(&cons_cond); pthread_cond_signal(&prod_cond); pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex); } } } }
Producer/Consumer Producer/Consumer #include <semaphore.h> #include <semaphore.h> #define N 10 #define N 10 int buffer[N]; int buffer[N]; int counter = 0, in = 0, out = 0, total = 0; int counter = 0, in = 0, out = 0, total = 0; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; sem_t semmutex; // sem_init(&semmutex, 0, 1); in main() sem_t semfull; // sem_init(&semfull, 0, 0); in main() sem_t semfull; // sem_init(&semfull, 0, 0); in main() sem_t semempty; // sem_init(&semempty, 0, N); in main() sem_t semempty; // sem_init(&semempty, 0, N); in main() void *producer(void *junk) { void *consumer(void *junk) { void *producer(void *junk) { void *consumer(void *junk) { while(1) { while(1) { while(1) { while(1) { sem_wait(&semempty); sem_wait(&semfull); sem_wait(&semempty); sem_wait(&semfull); pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex); sem_wait(&semmutex); sem_wait(&semmutex); buffer[in] = total++; printf("Consumed: %d\n", buffer[in] = total++; printf("Consumed: %d\n", printf("Produced: %d\n", buffer[out]); printf("Produced: %d\n", buffer[out]); buffer[in]); out = (out + 1) % N; buffer[in]); out = (out + 1) % N; in = (in + 1) % N; counter ‐‐ ; in = (in + 1) % N; counter ‐‐ ; counter++; counter++; pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex); sem_post(&semmutex); sem_post(&semmutex); sem_post(&semfull); sem_post(&semempty); sem_post(&semfull); sem_post(&semempty); } } } } } } } } Deadlock! #include <semaphore.h> #define N 10 int buffer[N]; int counter = 0, in = 0, out = 0, total = 0; sem_t semmutex; // sem_init(&semmutex, 0, 1); in main() sem_t semfull; // sem_init(&semfull, 0, 0); in main() sem_t semempty; // sem_init(&semempty, 0, N); in main() void *producer(void *junk) { void *consumer(void *junk) { while(1) { while(1) { sem_wait(&semmutex); sem_wait(&semmutex); sem_wait(&semempty); sem_wait(&semfull); buffer[in] = total++; printf("Consumed: %d\n", printf("Produced: %d\n", buffer[out]); buffer[in]); out = (out + 1) % N; in = (in + 1) % N; counter ‐‐ ; counter++; sem_post(&semfull); sem_post(&semempty); sem_post(&semmutex); sem_post(&semmutex); } } } }
Recommend
More recommend