Как работает эта реализация семафора? - PullRequest
3 голосов
/ 24 декабря 2010

Счастливого Рождества!

Я читаю Маленькая книга семафоров .В книге есть реализация семафоров на C, которую я не совсем понимаю.Смотрите код ниже.Существует эта переменная wakeups .Автор объясняет:

wakeups подсчитывает количество ожидающих сигналов;то есть количество потоков, которые были разбужены, но еще не возобновили выполнение.Причина пробуждений состоит в том, чтобы убедиться, что наши семафоры имеют свойство 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 ]

5 голосов
/ 25 декабря 2010

Элемент wakeups не предназначен для защиты мьютекса от захвата чем-либо, кроме ожидающего потока - он предназначен для предотвращения освобождения слишком большого количества потоков из функции sem_wait().

pthread_cond_signal() вызов функции, которую cond_signal() упаковывает, имеет в своей документации следующие операторы (выделение добавлено):

Функция pthread_cond_signal() должна разблокировать хотя бы один потоков, которые заблокированы в указанной условной переменной cond (если какие-либо потоки заблокированы в cond).

И:

Вкл.для многопроцессорной системы реализация pthread_cond_signal() может оказаться невозможной, чтобы избежать разблокировки более чем одного потока, заблокированного в условной переменной.

Так, например, возможно, что при 3потоки ожидают при условии, что два (или все три) могут быть освобождены при выполнении вызова cond_signal().Счетчик wakeups гарантирует, что из функции sem_wait() будет действительно только соответствующее количество потоков.Остальные останутся в цикле do / while и будут ждать условия снова.

0 голосов
/ 24 декабря 2010

Это свойство означает, что сигнальный поток должен освобождать процессор от имени одного из ожидающих потоков, если таковые имеются. pthread_cond_signal () гарантирует именно это и по той же причине.

Функция pthread_cond_signal () должна разблокировать хотя бы один из потоков, которые заблокированы в указанной условной переменной cond (если какие-либо потоки заблокированы в cond).

...