Когда процесс открывает именованный семафор, между ними устанавливается связь на уровне записи, которая создается системой. Функция sem_close() удаляет эту связь (то есть закрывает семафор), освобождает все выделенные на нее ресурсы и уменьшает счетчик ссылок на семафор.
#include
int sem_close(sem_t *
Возвращает 0 при успешном завершении или -1 при ошибке
Когда процесс завершается или выполняет вызов exec(), открытые им именованные семафоры автоматически закрываются. Закрытие семафора не приводит к его удалению. Для этого нужно использовать функцию sem_unlink().
49.2.3. Удаление именованного семафора
Функция sem_unlink() удаляет семафор с именем name и делает его кандидатом на удаление, которое происходит, когда все процессы перестают его использовать (удаление может случиться сразу же, если все другие процессы уже закрыли данный семафор).
#include
int sem_unlink(const char *
Возвращает 0 при успешном завершении или -1 при ошибке
Применение функции sem_unlink() продемонстрировано в листинге 49.2.
Листинг 49.2. Использование функции sem_unlink() для удаления именованного POSIX-семафора
psem/psem_unlink.c
#include
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
if (argc!= 2 || strcmp(argv[1], "-help") == 0)
usageErr("%s sem-name\n", argv[0]);
if (sem_unlink(argv[1]) == -1)
errExit("sem_unlink");
exit(EXIT_SUCCESS);
}
psem/psem_unlink.c
POSIX-семафор — целое число, которое не может быть меньше нуля. Операции с такими объектами имеют следующие особенности:
• функции sem_post() и sem_wait(), изменяющие значения семафоров, делают это для каждого семафора отдельно и не поддерживают групповых операций;
• функции sem_post() и sem_wait() инкрементируют и декрементируют значения семафоров ровно на 1;
• POSIX-семафоры не поддерживают операции ожидания нулевого значения.
Из всего вышесказанного может создаться следующее впечатление: POSIX-семафоры являются менее функциональными, чем, например, их аналоги из System V. Но это не так — с их помощью можно добиться тех же результатов, что и с семафорами из других стандартов. В некоторых ситуациях может потребоваться чуть больше усилий, но обычно использование POSIX-семафоров приводит к уменьшению объема кода.
49.3.1. Декрементация семафора
Функция sem_wait() декрементирует (уменьшает на 1) значение семафора, на который указывает аргумент sem.
#include
int
Возвращает 0 при успешном завершении или -1 при ошибке
Если семафор имеет значение больше нуля, то функция sem_wait() сразу же завершится. Когда семафор равен 0, функция sem_wait() заблокируется до тех пор, пока его значение не станет положительным; когда это случится, он будет декрементирован, а функция sem_wait() завершит свою работу.
При прерывании вызова sem_wait() с помощью обработчика сигнала он завершится ошибкой EINTR; использование флага SA_RESTART в вызове sigaction() (когда этот обработчик создавался) не будет играть никакой роли (в некоторых реализациях UNIX флаг SA_RESTART приводит к автоматическому перезапуску данного вызова).
Программа, показанная в листинге 49.3, предоставляет интерфейс командной строки к функции sem_wait(). Ее применение будет продемонстрировано чуть позже.
Листинг 49.3. Использование функции sem_wait() для декрементации POSIX-семафора
psem/psem_wait.c
#include
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
sem_t *sem;
if (argc < 2 || strcmp(argv[1], "-help") == 0)
usageErr("%s sem-name\n", argv[0]);
sem = sem_open(argv[1], 0);
if (sem == SEM_FAILED)
errExit("sem_open");
if (sem_wait(sem) == -1)
errExit("sem_wait");
printf("%ld sem_wait() succeeded\n", (long) getpid());
exit(EXIT_SUCCESS);
}
psem/psem_wait.c
Функция sem_trywait() является неблокирующей версией sem_wait().
#include
int sem_trywait(sem_t *
Возвращает 0 при успешном завершении или -1 при ошибке
Если декрементация не может быть выполнена немедленно, то вызов sem_trywait() завершается ошибкой EAGAIN.
Функция sem_timedwait() представляет собой еще одну разновидность sem_wait(). Она позволяет вызывающему процессу ограничить время блокирования вызова.
#define _XOPEN_SOURCE 600
#include
int sem_timedwait(sem_t *
Возвращает 0 при успешном завершении или -1 при ошибке
Если вызов sem_timedwait() не успевает выполнить декрементацию семафора за отведенное ему время, то завершается ошибкой ETIMEDOUT.