C 言語で sched_setaffinity 関数を使用する

胡金庫 2023年10月12日
  1. sched_setaffinity 関数を使用して、プロセスの実行を特定の CPU に制限する
  2. CPU_SET マクロを使用して、プロセスをバインドする CPU コアを指定する
C 言語で sched_setaffinity 関数を使用する

この記事では、C 言語で sched_setaffinity 関数を使用する方法のいくつかの方法について説明します。

sched_setaffinity 関数を使用して、プロセスの実行を特定の CPU に制限する

今日、マルチコアハードウェアはユビキタスであり、オペレーティングシステムはこれらのコアで同時に実行される複数のプロセスを管理する必要があります。プロセス/スレッドの実行の管理を処理するオペレーティングシステムの部分は、スケジューラと呼ばれます。スケジューラーは、既存のすべてのプロセス/スレッドを使用可能なコア全体に効率的に分散し、それに応じてタイムスライスを割り当てようとします。スケジューリングは、特定のシステムの主要なパフォーマンス保証であるため、オペレーティングシステムで最も難しい設計上の問題の 1つです。スケジューラと対話するための標準の C インターフェイスはありませんが、特定の OS は、いくつかのプロセススケジューリングパラメータを変更するためのシステムコールを提供します。

sched_setaffinity は GNUC ライブラリの一部であり、ほとんどが Linux 固有の機能に基づいています。この関数は、プロセスが実行に適格である CPU コアのセットを示すいわゆる CPU アフィニティマスクを設定します。sched_setaffinity は最初の引数として PID 値を取り、2 番目の引数として sizeof(cpu_set_t) を取ります。3 番目の引数はタイプ cpu_set_t であり、これは不透明な構造であり、<sched.h> ヘッダーの事前定義されたマクロを使用して操作する必要があります。ただし、これらの関数とマクロを使用できるようにするには、_GNU_SOURCE マクロを定義する必要があることに注意してください。次の例では、ユーザーから 3つの整数をコマンドライン引数として受け取り、それらを格納して、それぞれ親/子プロセスの CPU 番号といくつかのループ反復を表すプログラムを実装します。次に、CPU_ZERO マクロを使用して cpu_set_t 変数をクリアし、fork を呼び出して子プロセスを生成します。

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

#define errExit(msg)    \
  do {                  \
    perror(msg);        \
    exit(EXIT_FAILURE); \
  } while (0)

int main(int argc, char *argv[]) {
  cpu_set_t set;
  int parentCPU, childCPU, wstatus;
  long nloops;

  if (argc != 4) {
    fprintf(stderr, "Usage: %s parent-cpu child-cpu num-loops\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  parentCPU = strtol(argv[1], NULL, 0);
  childCPU = strtol(argv[2], NULL, 0);
  nloops = strtol(argv[3], NULL, 0);

  CPU_ZERO(&set);

  switch (fork()) {
    case -1:
      errExit("fork");

    case 0:
      CPU_SET(childCPU, &set);

      if (sched_setaffinity(getpid(), sizeof(set), &set) == -1)
        errExit("sched_setaffinity");

      for (int j = 0; j < nloops; j++) getpid();

      exit(EXIT_SUCCESS);

    default:
      CPU_SET(parentCPU, &set);

      if (sched_setaffinity(getpid(), sizeof(set), &set) == -1)
        errExit("sched_setaffinity");

      for (int j = 0; j < nloops; j++) getpid();

      wait(NULL);
      exit(EXIT_SUCCESS);
  }
}

CPU_SET マクロを使用して、プロセスをバインドする CPU コアを指定する

sched_setaffinity 関数は、プロセスまたはスレッドごとに呼び出されます。したがって、fork が戻ったら、親プロセスと子プロセスに異なる CPU マスクを指定できます。CPU_SET マクロは、以前にゼロ化された cpu_set_t 構造を変更し、その結果、それを sched_setaffinity 呼び出しに渡すために使用されます。各プロセスは、getpid を呼び出して CPU リソースを占有し、例のデモンストレーションを容易にするループを実行することに注意してください。親プロセスは、前の例では wait 呼び出しを使用し、次の例では waitpid を使用して子を待機します。実証された動作を観察したい場合は、Linux システムで広く利用可能な htop コマンドラインユーティリティを使用してシステムプロセスを監視できます。

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

#define errExit(msg)    \
  do {                  \
    perror(msg);        \
    exit(EXIT_FAILURE); \
  } while (0)

int main(int argc, char *argv[]) {
  cpu_set_t set;
  int parentCPU, childCPU, wstatus;
  long nloops;

  if (argc != 4) {
    fprintf(stderr, "Usage: %s parent-cpu child-cpu num-loops\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  parentCPU = strtol(argv[1], NULL, 0);
  childCPU = strtol(argv[2], NULL, 0);
  nloops = strtol(argv[3], NULL, 0);

  CPU_ZERO(&set);

  pid_t c_pid = fork();
  if (c_pid == -1) errExit("fork");

  switch (c_pid) {
    case -1:
      errExit("fork");

    case 0:
      CPU_SET(childCPU, &set);

      if (sched_setaffinity(getpid(), sizeof(set), &set) == -1)
        errExit("sched_setaffinity");

      for (int j = 0; j < nloops; j++) getpid();

      exit(EXIT_SUCCESS);

    default:
      CPU_SET(parentCPU, &set);

      if (sched_setaffinity(getpid(), sizeof(set), &set) == -1)
        errExit("sched_setaffinity");

      for (int j = 0; j < nloops; j++) getpid();

      if (waitpid(c_pid, &wstatus, WUNTRACED | WCONTINUED) == -1)
        errExit("waitpid");

      exit(EXIT_SUCCESS);
  }
}
著者: 胡金庫
胡金庫 avatar 胡金庫 avatar

DelftStack.comの創設者です。Jinku はロボティクスと自動車産業で8年以上働いています。自動テスト、リモートサーバーからのデータ収集、耐久テストからのレポート作成が必要となったとき、彼はコーディングスキルを磨きました。彼は電気/電子工学のバックグラウンドを持っていますが、組み込みエレクトロニクス、組み込みプログラミング、フロントエンド/バックエンドプログラミングへの関心を広げています。

LinkedIn Facebook

関連記事 - C Process