1

一定の割合のCPUを使用する小さなプログラムを書いています。基本的な戦略は、CPU使用率を継続的にチェックし、使用率のレベルが指定された値よりも高い場合はプロセスをスリープ状態にすることです。

さらに、私はMacOS(Linuxのようなproc / statなし、C#のPerformanceCounterなし)をtop使用しているため、別のスレッドでコマンドを実行し、そこからCPU使用率を取得する必要があります。

問題は、引数として小さな値を指定しても、CPUの使用率が非常に高くなることです。そして、いくつかの実験の後、それはマルチスレッドによる共有フィールドによって引き起こされたようです。

これが私のコード(コード1)と実験です:

(コード2)当初、シェルコマンドを使用すると使用率が非常に高くなると思ったので、の無限ループについてコメントしrun()、実行中のみを残しましたgetCpuUsage()。ただし、CPU使用率はほぼゼロです。

(コード3)次に、run()CPUの50%を使用することを目的としたcpuUsageから独立した別の関数を作成しました。それはうまくいきます!コード1とコード3の唯一の違いは、の使用法だと思いますcpuUsage。だから私はスレッド間でフィールドを共有することがCPUをたくさん使うのだろうかと思っていますか?

コード1

const char CPU_COMMAND[] = "top -stats cpu -l 1 -n 0| grep CPU\\ usage | cut -c 12-15";

int cpuUsage; // shared field that stores the cpu usage

// thread that continuously check CPU usage
// and store it in cpuUsage
void getCpuUsage() {
    char usage[3];
    FILE *out;
    while (1) {
        out = popen(CPU_COMMAND, "r");
        if (fgets(usage, 3, out) != NULL) {
            cpuUsage = atof(usage);
        } else {
            cpuUsage = 0;
        }
        pclose(out);
    }
}

// keep the CPU usage under ratio
void run(int ratio) {
    pthread_t id;
    int ret = pthread_create(&id, NULL, (void *)getCpuUsage, NULL);
    if (ret!=0) printf("thread error!");

    while (1) {
        // if current cpu usage is higher than ration, make it asleep
        if (cpuUsage > ratio) {
            usleep(10);
        }
    }

    pthread_join(id, NULL);
}

コード2

// keep the CPU usage under ratio
void run(int ratio) {
    pthread_t id;
    int ret = pthread_create(&id, NULL, (void *)getCpuUsage, NULL);
    if (ret!=0) printf("thread error!");

    /*while (1) {
        // if current cpu usage is higher than ration, make it asleep
        if (cpuUsage > ratio) {
            usleep(10);
        }
    }*/

    pthread_join(id, NULL);
}

コード3

void run() {
    const clock_t busyTime = 10;
    const clock_t idleTime = busyTime;

    while (1) {
        clock_t startTime = clock();
        while (clock() - startTime <= busyTime);
        usleep(idleTime);
    }
}
4

2 に答える 2

2

マルチスレッドCプログラムの共有フィールドはCPUを頻繁に使用しますか?

はい、複数のCPU上の複数のスレッドによる共有メモリ位置への/からの一定の読み取り/書き込みにより、キャッシュラインがCPU間を絶えず移動します(キャッシュバウンス)。IMO、これは、単純な「並列」アプリケーションのスケーラビリティが低い唯一の最も重要な理由です。

于 2012-11-23T15:22:13.367 に答える
1

Ok。Code1は、可能な限り高速にポペンを実行するスレッドを作成します。したがって、このスレッドはすべてのCPU時間を使い果たします。もう一方のスレッド(メインスレッド)はusleepを実行しますが、ポップアップスレッドは実行しません...

Code2はまた、このCPU使用スレッドを開始し、それが終了する(結合する)のを待ちます。これは決して起こりません。

Code3はしばらく実行された後、同じ量だけスリープするため、約50%を使用する必要があります。

つまり、基本的に何をすべきか(本当にその目的でtopを使用したい場合)、それを呼び出してから、たとえば1秒間、つまり100ミリ秒スリープし、code1のメインループが調整されるかどうかを確認します。

while (1) {
    usleep (100*1000);
    out = popen(CPU_COMMAND, "r");
于 2012-11-23T15:23:08.073 に答える