14

私はCで書かれたゲームサーバーを開発しています。そして、アルゴリズムを実行するために特定の頻度(1秒あたり50回)のサイクルを開発する必要があります。問題は、プログラムを正確な時間間隔(20000マイクロ秒)で一時停止できないことです。関数usleep(20000)は約30000マイクロ秒で実行されます。結果は常に予想よりも10000マイクロ秒長くなります。

これが私の簡単なコード例です。

#include <stdio.h>
#include <time.h>
#include <unistd.h>

int main( int argc, char ** argv )
{

        const unsigned long long nano = 1000000000;
        unsigned long long t1, t2;

        struct timespec tm;

        for(;;)
        {

                clock_gettime( CLOCK_REALTIME, &tm );
                t1 = tm.tv_nsec + tm.tv_sec * nano;

                usleep( 20000 );

                clock_gettime( CLOCK_REALTIME, &tm );
                t2 = tm.tv_nsec + tm.tv_sec * nano;

                printf( "delay: %ld\n", ( t2 - t1 ) / 1000 );
        }

        return 0;

}

そしてそれが実行された結果:

$ ./a.out
delay: 29233
delay: 29575
delay: 29621
delay: 29694
delay: 29688
delay: 29732
delay: 29709
delay: 29706
delay: 29666
delay: 29702
delay: 29702
delay: 29705
delay: 29789
delay: 29619
delay: 29785
delay: 29634
delay: 29692
delay: 29708
delay: 29701
delay: 29703

関数も使ってみましselect()たが、結果は。と同じsleep()です。

私に説明してください、私のコードの何が問題になっていますか。

ps:

$ uname -a
FreeBSD home.com 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Tue Jan  3 07:46:30 UTC 2012     root@farrell.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64
4

3 に答える 3

13

20000 u 秒間スリープする代わりに、clock_gettime の呼び出しに基づいて、再度実行するまでの残り時間だけスリープします。

すなわち:

usleep( lasttime+20000-now ); // But make sure you don't sleep when the result is negative

コードに問題があるわけではありませんが、実際のスリープの呼び出し、時間の読み取りなどには時間がかかり、正確なクロックサイクルの倍数でない限り、システムは正確な時間スリープすることはできません。

于 2012-10-08T07:41:50.077 に答える
11

非リアルタイム システムのスリープ関数は、指定された正確な期間スリープすることは保証されていません。ビジー状態のシステムでは、タイム スライスが開始されたときにのみプロセスが起動されます。または、マニュアル ページに記載されているように、「システム アクティビティにより、不確定な量だけスリープが長くなる場合があります」。

10ms に近い量は、VM セットアップに推奨されるkern.hzように、周波数が 100 に低下したように聞こえます。

この問題の古典的な回避策は、Ofir が提供するものです。一定のスリープ間隔を指定する代わりに、残りのスリープ時間を指定します。平均して、ループは 20 ミリ秒ごとに実行されます。これは、最も達成したいことです。

于 2012-10-08T07:51:34.480 に答える