在 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