SEM_WAIT - Linux手册页

时间:2019-08-20 18:01:15  来源:igfitidea点击:

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)。

InterfaceAttributeValue
sem_wait(),sem_trywait(),sem_timedwait()Thread safetyMT-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/