31 信号量

31.1 信号量:定义

  1. #include <semaphore.h>
  2. sem_t s;
  3. sem_init(&s, 0, 1);

Figure 31.1: Initializing A Semaphore

  1. int sem_wait(sem_t *s) {
  2. decrement the value of semaphore s by one
  3. wait if value of semaphore s is negative
  4. }
  5. int sem_post(sem_t *s) {
  6. increment the value of semaphore s by one
  7. if there are one or more threads waiting, wake one
  8. }

Figure 31.2: Semaphore: Definitions Of Wait And Post

  1. sem_t m;
  2. sem_init(&m, 0, X); // initialize semaphore to X; what should X be?
  3. sem_wait(&m);
  4. // critical section here
  5. sem_post(&m);

Figure 31.3: A Binary Semaphore (That Is, A Lock

31.2 二值信号量(锁)

31.3 信号量作为条件变量

  1. sem_t s;
  2. void *
  3. child(void *arg) {
  4. printf("child\n");
  5. sem_post(&s); // signal here: child is done
  6. return NULL;
  7. }
  8. int
  9. main(int argc, char *argv[]) {
  10. sem_init(&s, 0, X); // what should X be?
  11. printf("parent: begin\n");
  12. pthread_t c;
  13. Pthread_create(c, NULL, child, NULL);
  14. sem_wait(&s); // wait here for child
  15. printf("parent: end\n");
  16. return 0;
  17. }

Figure 31.6: A Parent Waiting For Its Child

31.4 生产者消费者(有界缓存)问题

  1. int buffer[MAX];
  2. int fill = 0;
  3. int use = 0;
  4. void put(int value) {
  5. buffer[fill] = value; // line f1
  6. fill = (fill + 1) % MAX; // line f2
  7. }
  8. int get() {
  9. int tmp = buffer[use]; // line g1
  10. use = (use + 1) % MAX; // line g2
  11. return tmp;
  12. }

Figure 31.9: The Put And Get Routines

  1. sem_t empty;
  2. sem_t full;
  3. void *producer(void *arg) {
  4. int i;
  5. for (i = 0; i < loops; i++) {
  6. sem_wait(&empty); // line P1
  7. put(i); // line P2
  8. sem_post(&full); // line P3
  9. }
  10. }
  11. void *consumer(void *arg) {
  12. int i, tmp = 0;
  13. while (tmp != -1) {
  14. sem_wait(&full); // line C1
  15. tmp = get(); // line C2
  16. sem_post(&empty); // line C3
  17. printf("%d\n", tmp);
  18. }
  19. }
  20. int main(int argc, char *argv[]) {
  21. // ...
  22. sem_init(&empty, 0, MAX); // MAX buffers are empty to begi
  23. sem_init(&full, 0, 0); // ... and 0 are full
  24. // ...
  25. }

Figure 31.10: Adding The Full And Empty Conditions

  1. sem_t empty;
  2. sem_t full;
  3. sem_t mutex;
  4. void *producer(void *arg) {
  5. int i;
  6. for (i = 0; i < loops; i++) {
  7. sem_wait(&mutex); // line p0 (NEW LINE)
  8. sem_wait(&empty); // line p1
  9. put(i); // line p2
  10. sem_post(&full); // line p3
  11. sem_post(&mutex); // line p4 (NEW LINE)
  12. }
  13. }
  14. void *consumer(void *arg) {
  15. int i;
  16. for (i = 0; i < loops; i++) {
  17. sem_wait(&mutex); // line c0 (NEW LINE)
  18. sem_wait(&full); // line c1
  19. int tmp = get(); // line c2
  20. sem_post(&empty); // line c3
  21. sem_post(&mutex); // line c4 (NEW LINE)
  22. printf("%d\n", tmp);
  23. }
  24. }
  25. int main(int argc, char *argv[]) {
  26. // ...
  27. sem_init(&empty, 0, MAX); // MAX buffers are empty to begin with...
  28. sem_init(&full, 0, 0); // ... and 0 are full
  29. sem_init(&mutex, 0, 1); // mutex=1 because it is a lock (NEW LINE)
  30. // ...
  31. }

Figure 31.11: Adding Mutual Exclusion (Incorrectly)

  1. sem_t empty;
  2. sem_t full;
  3. sem_t mutex;
  4. void *producer(void *arg) {
  5. int i;
  6. for (i = 0; i < loops; i++) {
  7. sem_wait(&empty); // line p1
  8. sem_wait(&mutex); // line p1.5 (MOVED MUTEX HERE...)
  9. put(i); // line p2
  10. sem_post(&mutex); // line p2.5 (... AND HERE)
  11. sem_post(&full); // line p3
  12. }
  13. }
  14. void *consumer(void *arg) {
  15. int i;
  16. for (i = 0; i < loops; i++) {
  17. sem_wait(&full); // line c1
  18. sem_wait(&mutex); // line c1.5 (MOVED MUTEX HERE...)
  19. int tmp = get(); // line c2
  20. sem_post(&mutex); // line c2.5 (... AND HERE)
  21. sem_post(&empty); // line c3
  22. printf("%d\n", tmp);
  23. }
  24. }
  25. int main(int argc, char *argv[]) {
  26. // ...
  27. sem_init(&empty, 0, MAX); // MAX buffers are empty to begin with...
  28. sem_init(&full, 0, 0); // ... and 0 are full
  29. sem_init(&mutex, 0, 1); // mutex=1 because it is a lock
  30. // ...
  31. }

Figure 31.12: Adding Mutual Exclusion (Correctly)

  1. typedef struct _rwlock_t {
  2. sem_t lock; // binary semaphore (basic lock)
  3. sem_t writelock; // used to allow ONE writer or MANY readers
  4. int readers; // count of readers reading in critical section
  5. } rwlock_t;
  6. void rwlock_init(rwlock_t *rw) {
  7. rw->readers = 0;
  8. sem_init(&rw->lock, 0, 1);
  9. sem_init(&rw->writelock, 0, 1);
  10. }
  11. void rwlock_acquire_readlock(rwlock_t *rw) {
  12. sem_wait(&rw->lock);
  13. rw->readers++;
  14. if (rw->readers == 1)
  15. sem_wait(&rw->writelock); // first reader acquires writelock
  16. sem_post(&rw->lock);
  17. }
  18. void rwlock_release_readlock(rwlock_t *rw) {
  19. sem_wait(&rw->lock);
  20. rw->readers--;
  21. if (rw->readers == 0)
  22. sem_post(&rw->writelock); // last reader releases writelock
  23. sem_post(&rw->lock);
  24. }
  25. void rwlock_acquire_writelock(rwlock_t *rw) {
  26. sem_wait(&rw->writelock);
  27. }
  28. void rwlock_release_writelock(rwlock_t *rw) {
  29. sem_post(&rw->writelock);
  30. }

Figure 31.13: A Simple Reader-Writer Lock

31.5 Reader-Writer Locks

31.6 The Dining Philosophers

  1. void getforks() {
  2. sem_wait(forks[left(p)]);
  3. sem_wait(forks[right(p)]);
  4. }
  5. void putforks() {
  6. sem_post(forks[left(p)]);
  7. sem_post(forks[right(p)]);
  8. }

Figure 31.15: The getforks() And putforks() Routines

  1. typedef struct __Zem_t {
  2. int value;
  3. pthread_cond_t cond;
  4. pthread_mutex_t lock;
  5. } Zem_t;
  6. // only one thread can call this
  7. void Zem_init(Zem_t *s, int value) {
  8. s->value = value;
  9. Cond_init(&s->cond);
  10. Mutex_init(&s->lock);
  11. }
  12. void Zem_wait(Zem_t *s) {
  13. Mutex_lock(&s->lock);
  14. while (s->value <= 0)
  15. Cond_wait(&s->cond, &s->lock);
  16. s->value--;
  17. Mutex_unlock(&s->lock);
  18. }
  19. void Zem_post(Zem_t *s) {
  20. Mutex_lock(&s->lock);
  21. s->value++;
  22. Cond_signal(&s->cond);
  23. Mutex_unlock(&s->lock);
  24. }

Figure 31.16: Implementing Zemaphores With Locks And CVs

31.7 How To Implement Semaphores

31.8 Summary