在 C 語言中使用 sched_setaffinity 函式

Jinku Hu 2023年1月30日 2021年3月21日
  1. 使用 sched_setaffinity 函式將程序執行限制在特定的 CPU 上
  2. 使用 CPU_SET 巨集指示 CPU 核心將程序繫結到
在 C 語言中使用 sched_setaffinity 函式

本文將介紹幾種如何在 C 語言中使用 sched_setaffinity 函式的方法。

使用 sched_setaffinity 函式將程序執行限制在特定的 CPU 上

如今,多核硬體無處不在,作業系統需要管理在這些核上同時執行的多個程序。作業系統中負責管理程序/執行緒執行的部分稱為排程程式。排程程式嘗試在可用核心之間有效地分配所有現有程序/執行緒,並相應地分配時間片。排程是作業系統中最困難的設計問題之一,因為它是給定系統的主要效能保證。沒有與排程程式互動的標準 C 介面,但是某些 OS 提供了系統呼叫來修改多個流程排程引數。

sched_setaffinity 是 GNU C 庫的一部分,它主要基於特定於 Linux 的功能。該函式設定所謂的 CPU 親和力掩碼,它表示可以在其上執行程序的 CPU 核心集。sched_setaffinity 將 PID 值作為第一個引數,並將 sizeof(cpu_set_t) 作為第二個引數。第三個引數是 cpu_set_t 型別,它是一個不透明的結構,需要使用 <sched.h> 標頭檔案中的預定義巨集進行操作。但是請注意,應定義 _GNU_SOURCE 巨集以使這些功能和巨集可用。在下面的示例中,我們實現了一個程式,該程式將來自使用者的三個整數用作命令列引數,並將其儲存以分別表示父/子程序 CPU 編號和幾次迴圈迭代。然後,使用 CPU_ZERO 巨集清除 cpu_set_t 變數,並呼叫 fork 產生一個子程序。

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.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 來等待子級。如果你想觀察所演示的行為,則可以使用 htop 命令列實用程式來觀察系統程序,該實用程式在 Linux 系統上廣泛使用。

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.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);
    }
}
Author: 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

相關文章 - C Process