这种信号量的实现如何工作?

时间:2010-12-24 11:58:23

标签: c multithreading mutex semaphore conditional-statements

圣诞快乐!

我正在阅读The Little Book of Semaphores。书中有一个C语言的实现,我并不完全理解。请参阅下面的代码。有这个唤醒变量。作者解释说:

  

唤醒计算待处理信号的数量;也就是说,已被唤醒但尚未恢复执行的线程数。唤醒的原因是为了确保我们的信号量具有属性3,如第4.3节所述

  

属性3:如果在线程执行信号时有线程在等待信号量,则必须唤醒其中一个等待线程。

好的,我想我理解了这个属性的含义。其中一个等待线程应该获取互斥锁而不是另一个(例如信令线程)。如果我错了,请纠正我。我不明白的是这个机制如何保证这个属性。我会说房产不保证。非等待进程仍有可能获得互斥锁。我错过了什么?

typedef struct {
  int value, wakeups;
  Mutex *mutex;
  Cond *cond;
} Semaphore;

// SEMAPHORE

Semaphore *make_semaphore (int value)
{
  Semaphore *semaphore = check_malloc (sizeof(Semaphore));
  semaphore->value = value;
  semaphore->wakeups = 0;
  semaphore->mutex = make_mutex ();
  semaphore->cond = make_cond ();
  return semaphore;
}

void sem_wait (Semaphore *semaphore)
{
  mutex_lock (semaphore->mutex);
  semaphore->value--;

  if (semaphore->value < 0) {
    do {
      cond_wait (semaphore->cond, semaphore->mutex);
    } while (semaphore->wakeups < 1);
    semaphore->wakeups--;
  }
  mutex_unlock (semaphore->mutex);
}

void sem_signal (Semaphore *semaphore)
{
  mutex_lock (semaphore->mutex);
  semaphore->value++;

  if (semaphore->value <= 0) {
    semaphore->wakeups++;
    cond_signal (semaphore->cond);
  }
  mutex_unlock (semaphore->mutex);
}

2 个答案:

答案 0 :(得分:5)

wakeups成员不是为了保护互斥锁不被等待线程以外的其他东西获取 - 它旨在防止从sem_wait()函数中释放太多线程。

pthread_cond_signal()包含的cond_signal()函数调用具有以下语句in its documentation(强调添加):

  

pthread_cond_signal()函数将取消阻止在指定条件变量cond上阻塞的至少一个线程(如果在cond上阻塞了任何线程)。

  

在多处理器上,pthread_cond_signal()的实现可能无法避免在条件变量上阻塞多个线程的阻塞。

举一个例子,当3个线程在这个条件上等待时,可能会在cond_signal()调用时释放两个(或全部三个)。 wakeups计数器确保只有适当数量的线程实际上使用sem_wait()函数。其他的将保留在do / while循环中并再次等待条件。

答案 1 :(得分:0)

这个属性意味着信令线程应该代表其中一个等待线程释放CPU,如果有的话。 pthread_cond_signal()完全保证了这一点,并出于同样的原因。

  

pthread_cond_signal()函数应取消阻塞至少一个在指定条件变量cond上被阻塞的线程(如果在cond上阻塞了任何线程)。