Verwendung von die Funktion sched_setaffinity in C

Jinku Hu 12 Oktober 2023
  1. Verwenden Sie die Funktion sched_setaffinity, um die Prozessausführung auf bestimmte CPUs zu beschränken
  2. Verwenden Sie das Makro CPU_SET, um die CPU-Kerne anzugeben, an die der Prozess gebunden werden soll
Verwendung von die Funktion sched_setaffinity in C

In diesem Artikel werden verschiedene Methoden zur Verwendung der Funktion sched_setaffinity in C erläutert.

Verwenden Sie die Funktion sched_setaffinity, um die Prozessausführung auf bestimmte CPUs zu beschränken

Heutzutage ist Multi-Core-Hardware allgegenwärtig, und Betriebssysteme müssen mehrere Prozesse verwalten, die gleichzeitig auf diesen Kernen ausgeführt werden. Der Teil des Betriebssystems, der sich mit der Verwaltung der Prozess- / Thread-Ausführung befasst, wird als Scheduler bezeichnet. Ein Scheduler versucht, alle vorhandenen Prozesse / Threads effizient auf die verfügbaren Kerne zu verteilen und die Zeitscheiben entsprechend zuzuweisen. Die Zeitplanung ist eines der schwierigsten Entwurfsprobleme in Betriebssystemen, da sie die Hauptleistungsgarantie für das jeweilige System darstellt. Es gibt keine Standard-C-Schnittstelle für die Interaktion mit dem Scheduler, aber bestimmte Betriebssysteme bieten Systemaufrufe zum Ändern mehrerer Prozessplanungsparameter.

sched_setaffinity ist Teil der GNU C-Bibliothek und basiert hauptsächlich auf Linux-spezifischen Funktionen. Die Funktion legt die sogenannte CPU-Affinitätsmaske fest, die den Satz von CPU-Kernen angibt, auf denen der Prozess ausgeführt werden kann. sched_setaffinity verwendet den PID-Wert als erstes Argument und sizeof(cpu_set_t) als zweites. Das dritte Argument ist vom Typ cpu_set_t und es ist eine undurchsichtige Struktur, die mithilfe der vordefinierten Makros aus dem Header <sched.h> bearbeitet werden muss. Beachten Sie jedoch, dass das Makro _GNU_SOURCE definiert werden sollte, um diese Funktionen und Makros verfügbar zu machen. Im folgenden Beispiel implementieren wir ein Programm, das drei Ganzzahlen vom Benutzer als Befehlszeilenargumente verwendet und diese speichert, um die CPU-Nummern des übergeordneten / untergeordneten Prozesses bzw. mehrere Schleifeniterationen darzustellen. Dann wird das Makro CPU_ZERO verwendet, um die Variable cpu_set_t zu löschen, und fork wird aufgerufen, um einen untergeordneten Prozess zu erzeugen.

#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);
  }
}

Verwenden Sie das Makro CPU_SET, um die CPU-Kerne anzugeben, an die der Prozess gebunden werden soll

Die Funktion sched_setaffinity wird pro Prozess oder Thread aufgerufen. Sobald die Verzweigung zurückkehrt, können wir die verschiedenen CPU-Masken für die übergeordneten und untergeordneten Prozesse angeben. Das Makro CPU_SET wird verwendet, um die zuvor auf Null gesetzte Struktur cpu_set_t zu ändern und sie folglich an den Aufruf sched_setaffinity zu übergeben. Beachten Sie, dass jeder Prozess eine Schleife ausführt, in der er getpid aufruft, um CPU-Ressourcen zu belegen und die Demonstration des Beispiels zu vereinfachen. Der übergeordnete Prozess wartet mit dem Aufruf wait im vorherigen Beispiel auf das untergeordnete Element und verwendet im nächsten Beispiel waitpid. Wenn Sie das demonstrierte Verhalten beobachten möchten, können Sie die Systemprozesse mit dem Befehlszeilenprogramm htop überwachen, das auf Linux-Systemen weit verbreitet ist.

#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);
  }
}
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Verwandter Artikel - C Process