/* Lamport's bakery algorithm */ /* Improve safety in the usage of shared resources among multiple threads by */ /* means of mutual exclusion */ /* Communications of the ACM, August 1974, Volume 17, Number 8, P.453 */ #include <pthread.h> #include <stdbool.h> #include <stdio.h> #define NUM_THREADS (20) #define NAN (0) /* invalid number */ /* The counter threads will increment */ static unsigned int c; /* This indicates if a thread is choosing a number */ static bool choosing[NUM_THREADS] = { false }; /* This is the priority system, the smallest enters the critical section */ static unsigned int numbers[NUM_THREADS] = { NAN }; /* must have been unbound */ static unsigned int max_in_numbers(void) { /* Retrieve the greatest number in numbers[] */ unsigned int max = 0; for (unsigned int i = 0 ; i < NUM_THREADS ; ++i) { if (numbers[i] > max) max = numbers[i]; } return max; } #define LESS(i, j) \ (numbers[j] < numbers[i]) || ((numbers[j] == numbers[i]) && (j < i)) /* i represent a single thread */ /* j is sequentially representing all the threads */ static void lock(unsigned int const i) { /* We are choosing our number */ choosing[i] = true; /* We have a maximum value number */ numbers[i] = 1 + max_in_numbers(); /* unsafe ? */ /* We chose our number */ choosing[i] = false; /* We will observe other threads */ for (unsigned int j = 0 ; j < NUM_THREADS ; ++j) { /* We are waiting for every other thread j to choose a number */ while (choosing[j] == true) { /* We are busy for an other thread j to choose its number */ } /* We are waiting other threads to have a chose number which is strictly */ /* less than ours */ while (numbers[j] != NAN && LESS(i, j)) { /* Waiting for an other thread j to have a smaller number than our */ } } /* At this point we have the smallest number of all the threads so we have */ /* priority to enter the critical section */ } static void unlock(unsigned int const i) { /* We reset our smallest number so an other thread can enter the critical */ /* section */ numbers[i] = NAN; } static void inc(void) { for (unsigned int i = 0 ; i < 5000 ; ++i) { c++; } } static void *inc_safe(void *args) { unsigned int tid = *(unsigned int *)args; lock(tid); inc(); unlock(tid); pthread_exit(0); } static void *inc_unsafe(void *args) { (void)args; inc(); pthread_exit(0); } int main() { unsigned int tid[NUM_THREADS]; pthread_t t[NUM_THREADS]; for (unsigned int i = 0 ; i < NUM_THREADS; ++i) tid[i] = i; c = 0; for (unsigned int i = 0 ; i < NUM_THREADS; ++i) pthread_create(&t[i], NULL, inc_unsafe, &tid[i]); for (unsigned int i = 0 ; i < NUM_THREADS; ++i) pthread_join(t[i], NULL); printf("counter (unsafe) = %d\n", c); c = 0; for (unsigned int i = 0 ; i < NUM_THREADS; ++i) pthread_create(&t[i], NULL, inc_safe, &tid[i]); for (unsigned int i = 0 ; i < NUM_THREADS; ++i) pthread_join(t[i], NULL); printf("counter (safe) = %d\n", c); }