Linux repositories inspector

sem_wait(3) - Russkiy

Linux
2019-03-06
Aliases: sem_timedwait(3), sem_timedwait(3), sem_timedwait(3), sem_timedwait(3), sem_timedwait(3), sem_timedwait(3), sem_trywait(3), sem_trywait(3), sem_trywait(3), sem_trywait(3), sem_trywait(3), sem_trywait(3)

man-pages-ru

Russian man pages from the Linux Documentation Project

manpages-dev

Manual pages about using GNU/Linux for development

man-pages

Linux kernel and C library user-space interface documentation

ИМЯ

sem_wait, sem_timedwait, sem_trywait - блокирует семафор

ОБЗОР

#include <semaphore.h>

int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
Компонуется при указании параметра -pthread.
Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):
sem_timedwait(): _POSIX_C_SOURCE >= 200112L

ОПИСАНИЕ

Функция sem_wait() уменьшает (блокирует) семафор, на который указывает sem. Если значение семафор больше нуля, то выполняется уменьшение и функция сразу завершается. Если значение семафора равно нулю, то вызов блокируется до тех пор, пока не станет возможным выполнить уменьшение (т. е., значение семафора не станет больше нуля), или пока не вызовется обработчик сигнала.
Функция sem_trywait() подобна sem_wait(), за исключением того, что если уменьшение нельзя выполнить сразу, то вызов завершается с ошибкой (errno становится равным EAGAIN), а не блокируется.
Функция sem_timedwait() подобна sem_wait(), за исключением того, что в abs_timeout задаётся ограничение по количеству времени, на которое вызов должен заблокироваться, если уменьшение невозможно выполнить сразу. Аргумент abs_timeout указывает на структуру, в которой задаётся абсолютное время ожидания в секундах и наносекундах, начиная с эпохи, 1970-01-01 00:00:00 +0000 (UTC). Эта структура определена следующим образом:
struct timespec {
time_t tv_sec; /* секунды */
long tv_nsec; /* наносекунды [0 .. 999999999] */ };
Если на момент вызова время ожидания уже истекло и семафор нельзя заблокировать сразу, то sem_timedwait() завершается с ошибкой просрочки (errno становится равным ETIMEDOUT).
Если операцию можно выполнить сразу, то sem_timedwait() никогда не завершится с ошибкой просрочки, независимо от значения abs_timeout. Кроме того, в этом случае не проверяется корректность abs_timeout.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении все функции возвращают 0; при ошибке значение семафора не изменяется, возвращается -1, а в errno указывается причина ошибки.

ОШИБКИ

EINTR Вызов был прерван обработчиком сигнала; смотрите signal(7).
EINVAL Значение sem не является корректным для семафора.
В sem_trywait() может возникать следующая дополнительная ошибка:
EAGAIN Операция не может быть выполнена без блокировки (т. е., значение семафор равно нулю).
В sem_timedwait() дополнительно могут возникать следующие ошибки:
EINVAL Значение abs_timeout.tv_nsecs меньше 0, или больше или равно 1000 миллионов.
ETIMEDOUT
Истёк период ожидания в вызове раньше возможности блокировки семафора.

АТРИБУТЫ

Описание терминов данного раздела смотрите в attributes(7).
Интерфейс Атрибут Значение
sem_wait(), sem_trywait(), sem_timedwait() Безвредность в нитях MT-Safe

СООТВЕТСТВИЕ СТАНДАРТАМ

POSIX.1-2001, POSIX.1-2008.

ПРИМЕР

Программа (несколько упрощённая), показанная ниже, работает с безымянным семафором. Она ожидает два аргумента командной строки. В первом аргументе задаётся значение в секундах, которое используется в будильнике для генерации сигнала SIGALRM. Этот обработчик выполняет sem_post(3) для увеличения семафора, которого ждёт в main() вызов sem_timedwait(). Во втором аргументе задаётся период ожидания в секундах для sem_timedwait(). Далее показано что происходит в двух разных запусках программы:
$ ./a.out 2 3 About to call sem_timedwait() sem_post() из обработчика sem_timedwait() выполнена успешно $ ./a.out 2 1 About to call sem_timedwait() истекло время ожидания sem_timedwait()

Исходный код программы

#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <semaphore.h> #include <time.h> #include <assert.h> #include <errno.h> #include <signal.h>
sem_t sem;
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
static void handler(int sig) {
write(STDOUT_FILENO, "sem_post() из обработчика\n", 24);
if (sem_post(&sem) == -1) {
write(STDERR_FILENO, "ошибка sem_post()\n", 18);
_exit(EXIT_FAILURE);
} }
int main(int argc, char *argv[]) {
struct sigaction sa;
struct timespec ts;
int s;
if (argc != 3) {
fprintf(stderr, "Использование: %s <alarm-secs> <wait-secs>\n",
argv[0]);
exit(EXIT_FAILURE);
}
if (sem_init(&sem, 0, 0) == -1)
handle_error("sem_init");
/* установка обработчика SIGALRM; зададим таймер будильника,
используя argv[1] */
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGALRM, &sa, NULL) == -1)
handle_error("sigaction");
alarm(atoi(argv[1]));
/* вычисляем относительный интервал как текущее время плюс
количество секунд из argv[2] */
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
handle_error("clock_gettime");
ts.tv_sec += atoi(argv[2]);
printf("в main() вызывается sem_timedwait()\n");
while ((s = sem_timedwait(&sem, &ts)) == -1 && errno == EINTR)
continue; /* перезапускаем, если прервано обработчиком */
/* проверяем что произошло */
if (s == -1) {
if (errno == ETIMEDOUT)
printf("истекло время ожидания sem_timedwait()\n");
else
perror("sem_timedwait");
} else
printf("sem_timedwait() выполнена успешно\n");
exit((s == 0) ? EXIT_SUCCESS : EXIT_FAILURE); }
⇧ Top