SEM_WAIT - Linux手册页
Linux程序员手册 第3部分
更新日期: 2020-06-09
名称
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()相同,不同之处在于,如果无法立即执行减量,则调用将返回错误(错误号设置为EAGAIN)而不是阻塞。
sem_timedwait()与sem_wait()相同,不同之处在于abs_timeout指定了在无法立即执行减量操作时调用应阻塞的时间限制。 abs_timeout参数指向一个结构,该结构指定自1970年1月1日00:00:00 +0000(UTC)以来的绝对超时(以秒和纳秒为单位)。此结构定义如下:
struct timespec { time_t tv_sec; /* Seconds */ long tv_nsec; /* Nanoseconds [0 .. 999999999] */ };
如果超时已在调用时到期,并且信号无法立即锁定,则sem_timedwait()会失败,并显示超时错误(将errno设置为ETIMEDOUT)。
如果可以立即执行该操作,则无论abs_timeout的值如何,sem_timedwait()都不会因超时错误而失败。此外,在这种情况下不检查abs_timeout的有效性。
返回值
所有这些函数成功均返回0;否则,返回0。如果发生错误,则信号量的值保持不变,返回-1,并设置errno表示错误。
错误说明
- EINTR
- 呼叫被信号处理程序中断;参见signal(7)。
- EINVAL
- sem不是有效的信号量。
sem_trywait()可能会发生以下附加错误:
- EAGAIN
- 没有阻塞就无法执行该操作(即,信号量当前值为零)。
sem_timedwait()可能会发生以下其他错误:
- EINVAL
- abs_timeout.tv_nsecs的值小于0,或大于或等于10亿。
- ETIMEDOUT
- 在锁定信号灯之前,呼叫已超时。
属性
有关本节中使用的术语的说明,请参见attribute(7)。
Interface | Attribute | Value |
sem_wait(),sem_trywait(),sem_timedwait() | Thread safety | MT-Safe |
遵循规范
POSIX.1-2001,POSIX.1-2008。
示例
下面显示的(有点琐碎)程序在未命名的信号灯上运行。该程序需要两个命令行参数。第一个参数指定一个秒值,该值用于设置警报计时器以生成SIGALRM信号。该处理程序执行sem_post(3)来增加使用sem_timedwait()在main()中等待的信号量。第二个命令行参数指定sem_timedwait()的超时长度(以秒为单位)。下面显示了在该程序的两次不同运行中发生的情况:
$ ./a.out 2 3 About to call sem_timedwait() sem_post() from handler sem_timedwait() succeeded $ ./a.out 2 1 About to call sem_timedwait() sem_timedwait() timed out
Program source
#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() from handler\n", 24); if (sem_post(&sem) == -1) { write(STDERR_FILENO, "sem_post() failed\n", 18); _exit(EXIT_FAILURE); } } int main(int argc, char *argv[]) { struct sigaction sa; struct timespec ts; int s; if (argc != 3) { fprintf(stderr, "Usage: %s <alarm-secs> <wait-secs>\n", argv[0]); exit(EXIT_FAILURE); } if (sem_init(&sem, 0, 0) == -1) handle_error("sem_init"); /* Establish SIGALRM handler; set alarm timer using 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])); /* Calculate relative interval as current time plus number of seconds given argv[2] */ if (clock_gettime(CLOCK_REALTIME, &ts) == -1) handle_error("clock_gettime"); ts.tv_sec += atoi(argv[2]); printf("main() about to call sem_timedwait()\n"); while ((s = sem_timedwait(&sem, &ts)) == -1 && errno == EINTR) continue; /* Restart if interrupted by handler */ /* Check what happened */ if (s == -1) { if (errno == ETIMEDOUT) printf("sem_timedwait() timed out\n"); else perror("sem_timedwait"); } else printf("sem_timedwait() succeeded\n"); exit((s == 0) ? EXIT_SUCCESS : EXIT_FAILURE); }
另外参见
clock_gettime(2),sem_getvalue(3),sem_post(3),sem_overview(7),时间(7)
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。