nanosleep

目次

うたたね…

パート 3 として, nanosleep(2) を使います. 名前から容易に想像できるように, ナノ秒 (0.000000001 秒!) 単位で動作を止めることができる (?) 関数です. 使い方は, 止めたい時間を指定した struct timespec な変数 req に対して, nanosleep(&req, NULL) とすれば OK です.

struct timespec は, time_t な要素 tv_seclong な要素 tv_nsec から成り, 前者に秒単位, 後者にナノ秒単位で止める時間を指定します.

man nanosleep の BUGS を読むとわかりますが, the normal kernel timer mechanism に基づいているので, 引数に指定された秒数に加えて, 休んでいたプロセスが実行可能になるまでの時間 (10 ミリ秒程度) が余計にかかるようです.

時を計りしもの

おなじみ (?) の gettimeofday(2) を使います.

プログラム例

SLEEP_NSEC ナノ秒だけ休んで時間を計測するというループを LOOP 回繰り返すという, 今までと同じプログラム. 11 行目では 20000000 ナノ秒 = 20 ミリ秒を設定しています. 21,22 行目で,nanosleep に渡す引数 treq を作成しています.

 1  /*
 2   * test_nanosleep.c
 3   * nanosleep を使って, 間隔をあけるテスト
 4   */
 5
 6  #include <stdio.h>
 7  #include <unistd.h>
 8  #include <sys/time.h>
 9  #include <time.h>
10
11  #define SLEEP_NSEC 20000000
12  #define LOOP 10
13
14  int main()
15  {
16    int i;
17    struct timeval tv[LOOP];
18    struct timezone tz;
19    struct timespec treq, trem;
20
21    treq.tv_sec = (time_t)0;
22    treq.tv_nsec = SLEEP_NSEC;
23
24    for(i=0; i<LOOP; i++){
25      nanosleep(&treq, &trem);
26      gettimeofday(tv + i, &tz);
27    }
28
29    for(i=0; i<LOOP; i++){
30      printf("%3d : %ld:%06ld\n", i, tv[i].tv_sec, tv[i].tv_usec);
31    }
32
33    return 0;
34  }

実行結果

まずは実行結果. よく見ると, 30 ミリ秒の間隔が空いています. やっぱり, 指定した 20 ミリ秒に加えて, 10 ミリ秒が余計にかかっているようです.

  0 : 890377532:454773
  1 : 890377532:484678
  2 : 890377532:514672
  3 : 890377532:544669
  4 : 890377532:574668
  5 : 890377532:604672
  6 : 890377532:634669
  7 : 890377532:664669
  8 : 890377532:694704
  9 : 890377532:724671

次の例は, SLEEP_NSEC を 200 ミリ秒にしてみました. やぁっぱり 210 ミリ秒の間隔になってますねぇ. しかも, マイクロ秒の位 (下から 3 桁) がほぼ揃っているのがニクイですね.

  0 : 890378510:824762
  1 : 890378511:034672
  2 : 890378511:244678
  3 : 890378511:454669
  4 : 890378511:664667
  5 : 890378511:874668
  6 : 890378512:084669
  7 : 890378512:294666
  8 : 890378512:504667
  9 : 890378512:714675


[うさぎ]

m@sa.to