9

次のコードを検討してください。

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

// Compile with gcc -lrt -lm -o test_clock test_clock.c

#define CLOCK CLOCK_MONOTONIC

int main(int argc, char** argv) {
    double temp, elapsed;
    int j;
    struct timespec requestStart, requestEnd, req;

    // Pseudo-sleep
    clock_gettime(CLOCK, &requestStart);
    temp = 0;
    for(j=0; j < 40; j++)
        temp += sin(j);
    clock_gettime(CLOCK, &requestEnd);
    elapsed = ( requestEnd.tv_sec - requestStart.tv_sec ) / 1e-6
                 + ( requestEnd.tv_nsec - requestStart.tv_nsec ) / 1e3;
    printf("Elapsed: %lf us\n", elapsed);

    // Nanosleep
    clock_gettime(CLOCK, &requestStart);
    req.tv_nsec = 5000;
    req.tv_sec = 0;
    clock_nanosleep(CLOCK, 0, &req, NULL);
    clock_gettime(CLOCK, &requestEnd);
    elapsed = ( requestEnd.tv_sec - requestStart.tv_sec ) / 1e-6
                 + ( requestEnd.tv_nsec - requestStart.tv_nsec ) / 1e3;

    printf("Elapsed: %lf us\n", elapsed);

}

私の2.6.32システムでは、結果は次のようになります。

Elapsed: 5.308000 us
Elapsed: 69.142000 us

nanosleep()がカーネルにプロセスの再スケジュールを要求するため、これが最も可能性が高いことに同意します。どうすればこれを回避できますか?CPUの所有権を維持し、正確な時間だけアイドル状態にしたい。

4

7 に答える 7

10

アプリケーションを可能な限り正確に「スリープ」できるようにする場合は、最初にアプリケーションをリアルタイムの状態にします。

  • プログラム/スレッドにリアルタイムスケジューラクラスを使用する:SCHED_FIFOまたはSCHED_RR
  • プログラム/スレッドの優先度を上げる
  • カーネルが処理する最小量よりも少ない時間「スリープ」する場合は、手動でビジーウェイトします。

http://www.drdobbs.com/184402031をご覧ください

そして、この他の質問:nanosleepの高いCPU使用率?

于 2011-02-13T22:31:43.970 に答える
8

OSスケジューラは、「ああ、このスレッドをプロセッサから正確に86クロックサイクル離してから、再びオンにする」のようなことはしません。

あなたはプロセッサをあきらめました、あなたはプロセッサをあきらめました。OSは、気が向いたら元に戻します。他に実行されているものがプロセッサを放棄するまで待たなければならない可能性があります。

于 2011-02-13T20:59:31.303 に答える
2

まあ、manページが部分的に述べているので、あなたはそれと一緒に暮らすことを学ぶ必要があるでしょう: the actual time slept may be longer, due to system latencies and possible limitations in the timer resolution of the hardware:-)

さて、あなたの質問に対する答えについてですが、私の一番の推測は、最初のループがインプロセスで実行されているためだと思います。つまり、CPUをフラットに実行しているため、コンテキストスイッチは必要なく、スケジューラーから提供された100ミリ秒のクォンタム内ですべての作業を実行します。

ただし、nanosleep明示的にスリープ状態にするように要求しているため、スイッチが切れる可能性が高くなります。while期間が終了するまでプロセスをタイトなループに入れるほど非効率的ではありません:-)

つまり、別のプロセスがそのクォンタムを完全に使い果たしてしまう可能性があるという事実を含め、スケジューラのすべての気まぐれにさらされることになります。したがって、プロセスは少なくとも100ミリ秒間そこから外れる可能性があります。負荷の高いシステムでは、かなりの時間がかかる可能性があります。

于 2011-02-13T21:04:46.627 に答える
2
// busy wait for 10 microseconds
struct timespec ttime,curtime;

// get the time
clock_gettime(CLOCK_REALTIME,&ttime);

// clear the nanoseconds and keep the seconds in order not to overflow the nanoseconds
ttime.tv_nsec = 0;

// set it back
clock_settime(CLOCK_REALTIME,&ttime);

// get the time again 
clock_gettime(CLOCK_REALTIME,&ttime);

// increase the nano seconds by 10*1000
ttime.tv_nsec += 10000;

// loop
while(true){
  clock_gettime(CLOCK_REALTIME,&curtime);
  if (curtime.tv_nsec > ttime.tv_nsec)
    break;
}

//usleepよりもはるかに優れています。

于 2014-07-08T20:55:06.280 に答える
1

メソッドを使用usleepして、マイクロ秒単位でスリープを取得できます。

于 2012-10-09T05:47:05.603 に答える
0

効率-数クロックサイクルの精度でタスクの切り替えを可能にするOSは、他にはほとんど何もしません。

これを行う特殊なOSがありますが、通常のハードウェアでは、ハイパーバイザーに多くのオーバーヘッドを支払います

于 2011-02-13T21:07:21.577 に答える
0

これは保持している答えです-私は関連するLinuxの内部を知りません、うまくいけば専門家がやって来てそれを片付けることができます。

1つの可能性は、69usが、スレッドのスケジュールを解除してから再スケジュールするという単なるオーバーヘッドであるということです。スリープが短い場合でも、カーネルはコンテキストスイッチ(またはスケジュールするものがない場合はコンテキストスイッチの半分)を実行するために多くの作業を実行し、ほとんどすぐに元に戻す可能性があります。それが典型的なPCのLinuxでどれくらいの時間がかかるのかわかりません。

それがそれを説明しない場合、スケジューラーは一般に「タイムスライス」の概念を持っています。これは、スケジューラーがそれ自体をスケジュール解除するか、またはより高い何かをしない限り、スケジューラーがそれを切り替えることを考える前に、スケジュールされたスレッドが実行されるために残される時間です。優先順位がスケジュール可能になります。カーネルには、タイムスライスの最後に割り込みを発生させる低レベルのタイマーがあります(スレッドのブロックを解除する可能性のあるI / Oなどの他の特定のイベントに対して発生する割り込みに加えて)。タイムスライスが終了すると、スケジューラーは同じスレッドを続行するか、別のスレッドに切り替えるかを決定できます。

したがって、スリープ状態のときは、(a)スケジューラーが、要求された時間にスレッドをスケジュール可能にするタイマーを実際に設定しておらず、タイムスライスを待機しているだけであるため、CPUが必要以上に長くアイドル状態になっているように見えます。 ; または(b)要求された時間にスレッドをスケジュール可能にしますが、スリープによって実行を断念すると、同じ優先度の他のスレッドが入り、スケジューラーは「あなたの番になるまで、スレッドよりも優先する理由がありません。 「これも、スケジューラーがスケジュールするスレッドを決定するために通常使用するルールに従います。

ただし、69usはタイムスライシングのアーティファクトとしてはかなり短いです。

あなたは基本的な解決策を持っているようです-スピンロックのように、時間をチェックするループに座って非常に短い期間遅延させることができます。ただし、他のすべての人が言っているように、非リアルタイムシステムでは、定義上、スケジューラーが特定の時間にスレッドを実行することを要求することはできません。リアルタイムシステムでも、同じ優先度のスレッドと競合している場合は負ける可能性があり、より高い優先度のスレッドと競合している場合は負ける可能性があります

于 2011-02-13T22:22:41.480 に答える