名 前
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 || _XOPEN_SOURCE >= 600
説 明
sem_wait() は sem が 指 す セ マ フ ォ の 値 を 1 減 ら す (ロ ッ ク す る )。 セ マ フ ォ の 値 が 0 よ り 大 き い 場 合 、 減 算 が 実 行 さ れ 、 関 数 は 直 ち に 復 帰 す る 。 セ マ フ ォ の 現 在 値 が 0 の 場 合 に は 、 減 算 を 実 行 で き る よ う に な る (つ ま り 、 セ マ フ ォ の 値 が 0 よ り 大 き な 値 に な る ) ま で 、 も し く は シ グ ナ ル ハ ン ド ラ ー に よ っ て 呼 び 出 し が 中 断 さ れ る ま で 、 関 数 呼 び 出 し は 停 止 (block) す る 。
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 の 正 当 性
の 検 査 は 行 わ
れ な い 。
返 り 値
成 功 す る と 、 こ れ ら の 関 数 は 0 を 返 す 。 エ ラ ー の 場 合 、 セ マ フ ォ の 値 を 変 更 せ ず に 、 −1 を 返 し 、 errno に エ ラ ー を 示 す 値 を セ ッ ト す る 。
エ ラ ー
EINTR 呼 び 出 し は シ グ ナ ル ハ ン ド ラ ー に よ り 中 断 さ れ た 。 |
signal(7) 参 照 。 | ||
EINVAL |
sem は 有 効 な セ マ フ ォ で は な い 。
sem_trywait() の 場 合 に は 、 上 記 に 加 え て 以 下 の エ ラ ー も 起 こ る 。
EAGAIN 停 止 |
(block) せ ず に ロ ッ ク 操 作 を 完 了 で き な か っ た (つ ま り 、 セ マ |
フ ォ の 現 在 の 値 が 0 で あ っ た )。
sem_timedwait() の 場 合 、 以 下 の エ ラ ー も 起 こ る 。
EINVAL |
abs_timeout.tv_nsecs の 値 が 0 未 満 、 も し く は 1,000,000,000 以 上 で あ る 。 |
ETIMEDOUT セ マ フ ォ の ロ ッ ク に 成 功 す る 前 に 時 間 切 れ と な っ た 。
属 性
マ ル チ ス レ ッ デ ィ ン グ (pthreads(7) 参 照 ) 関 数 sem_wait(), sem_trywait(), sem_timedwait() は ス レ ッ ド セ ー フ で あ る 。
準 拠
POSIX.1−2001.
注 意
シ グ ナ ル ハ ン ド ラ ー は 、 sigaction(2) の SA_RESTART フ ラ グ を 使 用 し て い る か ど う か に 関 わ ら ず 、 こ れ ら の 関 数 の 呼 び 出 し が 停 止 し て い る 場 合 、 シ グ ナ ル ハ ン ド ラ ー に よ り 常 に 中 断 さ れ る 。
例
以 下 に 示 す (ち ょ っ と し た ) プ ロ グ ラ ム は 名 前 な し セ マ フ ォ の 操 作 を 行 う 。 プ ロ グ ラ ム は コ マ ン ド ラ イ ン 引 き 数 を 2 つ 取 る 。 最 初 の 引 き 数 に は 、 SIGALRM シ グ ナ ル を 生 成 す る た め の ア ラ ー ム タ イ マ ー の 設 定 に 使 わ れ る 値 を 秒 単 位 で 指 定 す る 。 こ の シ グ ナ ル ハ ン ド ラ ー は 、 main() 内 で sem_timedwait() を 使 っ て 待 っ て い る セ マ フ ォ を 、 sem_post(3) を 使 っ て 加 算 す る 。 2番 目 の 引 き 数 に は 、 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 プ ロ グ
ラ ム の ソ ー
ス
#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), time(7)
こ の 文 書 に つ い て
こ の man ペ ー ジ は Linux man−pages プ ロ ジ ェ ク ト の リ リ ー ス 3.79 の 一 部 で あ る 。 プ ロ ジ ェ ク ト の 説 明 と バ グ 報 告 に 関 す る 情 報 は http://www.kernel.org/doc/man−pages/ に 書 か れ て い る 。