Provided by: manpages-ja-dev_0.5.0.0.20221215+dfsg-1_all bug

名前

       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 が指すセマフォの値を 1 減らす (ロックする)。 セマフォの値が 0 より大き
       い場合、減算が実行され、関数は直ちに復帰する。 セマフォの現在値が 0 の場合には、減算を実行
       できるようになる (つまり、セマフォの値が 0 より大きな値になる) まで、もしくは シグナルハン
       ドラーによって呼び出しが中断されるまで、 関数呼び出しは停止 (block) する。

       sem_trywait()  は sem_wait()  と同じだが、セマフォ値の減算をすぐに実行できなかった場合に、
       停止 (block) するのではなくエラーで復帰する (errnoEAGAIN がセットされる) 点が異なる。

       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() はタイムアウトエラー (errnoETIMEDOUT がセットさ
       れる) で失敗する。

       セマフォ操作がすぐに実行できるときは、 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
              セマフォのロックに成功する前に時間切れとなった。

属性

       この節で使用されている用語の説明については、 attributes(7) を参照。

       ┌───────────────────────────┬───────────────┬─────────┐
       │インターフェース属性      │
       ├───────────────────────────┼───────────────┼─────────┤
       │sem_wait(), sem_trywait(), │ Thread safety │ MT-Safe │
       │sem_timedwait()            │               │         │
       └───────────────────────────┴───────────────┴─────────┘

準拠

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

       以下に示す (ちょっとした) プログラムは名前なしセマフォの操作を行う。  プログラムはコマンド
       ライン引数を  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 プロジェクトのリリース 5.10 の一部である。プロジェクトの
       説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。