Subject: How do I sleep() in a C program for less than one second?
Date: Thu Mar 18 17:16:55 EST 1993

4.6) C のプログラム中で1秒以下の時間 sleep() するにはどうすれば いいでしょうか。

まず、指定できる秒数というのは "最小" の sleep 時間であるに過ぎない、 ということに注意して下さい。実際の sleep 時間はシステムのロードなどスケ ジューリングの結果に依存しますので、運が悪ければかなり長くなってしまい ます。

あらゆる環境で使える "うたたね(napping)" (短い時間眠ることをこういいま す) するための標準的なライブラリ関数は存在しません。"usleep(n)" という n マイクロ秒間実行を停止する関数を提供している環境もいくつかあります。 もし、usleep() を使えない環境にいらっしゃるのでしたら、以下に BSD 版と System V版の2つの実装を載せておきますので、お使い下さいませ。

以下に挙げるコードは Doug Gwyn の 4BSDのための の System V エミュレー ションサポートから抜き出してきたものです。 原本では Doug はこの関数を 'nap()' と呼んでいます。この関数を "usleep()"と呼ぶとよろしいのではない でしょうか。

/*
    usleep -- 4.2 BSD のためのシステムコールエミュレーション
    サポートルーチン
    last edit:29-Oct-1984D A Gwyn
*/
extern intselect();

int
usleep( usec )/* returns 0 if ok, else -1 */
    longusec;/* delay in microseconds */
    {
    static struct/* 'timeval' */
    {
    longtv_sec;/* seconds */
    longtv_usec;/* microsecs */
    }delay;/* _select() timeout */

    delay.tv_sec = usec / 1000000L;
    delay.tv_usec = usec % 1000000L;

    return select( 0, (long *)0, (long *)0, (long *)0, &delay );
    }
System V 上での例を以下に挙げます:
    
/*
System V(または poll()を持っているシステム) のための1秒以下の sleep
Don Libes, 4/1/1991

poll() にはミリ秒単位で指定しますが、BSD でこの関数に似たものを作ろうと
する場合にはマイクロ秒待ちのものになります。互換性のため、この関数は実
際に要求された値をミリ秒に丸めています。また、複数回の関数呼び出しに
渡ってマイクロ秒を積算して "長い時間に渡る" 正確性を提供します。そのた
め、この関数は tight loop 内で呼び出されるでしょうし、長い時間に渡って
いるのでエラーが平均化するだろう、という考えに基づきます。

いずれにしても、もしこの関数を tight loop ではない場所で呼んでいる場合
には、ほとんど疑いなくマイクロ秒の分解能の要求をしていない、ということ
です。この場合、その要求はマイクロ秒を気にしていません。そして、もしそ
のようなことをしていたとしたら、それはあまり UNIX を活用していない、と
いうことです。というのは、ランダムなシステムの消化不良 (スケジューリン
グのような) はタイミングに依存したコードをめちゃくちゃにしてしまうから
です。

タイムアウトに成功したら、0 が返ってきます。失敗の場合には -1 が返りま
す。
*/

#include <poll.h>

int
usleep(usec)
unsigned int usec;/* microseconds */
{
    static subtotal = 0;/* microseconds */
    int msec;/* milliseconds */

    /* 'foo' is only here because some versions of 5.3 have
     * a bug where the first argument to poll() is checked
     * for a valid memory address even if the second argument is 0.
     */
    struct pollfd foo;

    subtotal += usec;
    /* if less then 1 msec request, do nothing but remember it */
    if (subtotal < 1000) return(0);
    msec = subtotal/1000;
    subtotal = subtotal%1000;
    return poll(&foo,(unsigned long)0,msec);
}
他に、System V や他の BSD でない UNIX 環境 (non-BSD Unices:-)) で、この ような "うたたね" をするために使えそうなものは、comp.sources.misc の volume 4 に投稿された Jon Zeeff の s5nap パッケージでしょう。これはデバ イスドライバのインストールを必要としますが、一度インストールしてしまえ ば完璧に動作します(このパッケージはカーネルの delay() ルーチンを使用し ているため、sleep 分解能はカーネルの HZ 値に制限されます)。


UNIX FAQ LIST / Copyright(c)1994,Ted Timar / tmatimar@isgtec.com


Maintainer: あさだ たくや