nanosleepパート 3 として, nanosleep(2) を使います.
名前から容易に想像できるように, ナノ秒 (0.000000001 秒!)
単位で動作を止めることができる (?) 関数です. 使い方は,
止めたい時間を指定した struct timespec な変数
req に対して, nanosleep(&req, NULL)
とすれば OK です.
struct timespec は,
time_t な要素 tv_sec と
long な要素 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
![[うさぎ]](../../image/usagi/usa-s.png)
Copyright (C) 1998, Masahiro SATO