Verwendung von die Funktion sched_setaffinity in C
-
Verwenden Sie die Funktion
sched_setaffinity
, um die Prozessausführung auf bestimmte CPUs zu beschränken -
Verwenden Sie das Makro
CPU_SET
, um die CPU-Kerne anzugeben, an die der Prozess gebunden werden soll
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);
}
}
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