在 C 语言中使用 sched_setaffinity 函数

Jinku Hu 2023年10月12日
  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 <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 来等待子级。如果你想观察所演示的行为,则可以使用 htop 命令行实用程序来观察系统进程,该实用程序在 Linux 系统上广泛使用。

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

DelftStack.com 创始人。Jinku 在机器人和汽车行业工作了8多年。他在自动测试、远程测试及从耐久性测试中创建报告时磨练了自己的编程技能。他拥有电气/电子工程背景,但他也扩展了自己的兴趣到嵌入式电子、嵌入式编程以及前端和后端编程。

LinkedIn Facebook

相关文章 - C Process