#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_trywait() は sem_wait() と同じだが、セマフォ値の減算をすぐに実行できなかった場合に、 停止 (block) するのではなくエラーで復帰する (errno に EAGAIN がセットされる) 点が異なる。
sem_timedwait() は sem_wait() と同じだが、セマフォ値の減算をすぐに実行できなかった場合に 関数呼び出しが停止する時間の上限を abs_timeout で指定する点が異なる。 abs_timeout 引数は、タイムアウト時刻を指定する構造体へのポインターである。 この構造体には、タイムアウト時刻を時刻紀元 (Epoch; 1970-01-01 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 の正当性の検査は行われない。
sem_trywait() の場合には、上記に加えて以下のエラーも起こる。
sem_timedwait() の場合、以下のエラーも起こる。
インターフェース | 属性 | 値 |
sem_wait(), sem_trywait(), sem_timedwait() | Thread safety | MT-Safe |
$ ./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
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);
}