Linux上将进程、线程与CPU核绑定

      CPU亲和性(CPU Affinity)是某一进程(或线程)绑定到特定的CPU核(或CPU集合),从而使得该进程(或线程)只能运行在绑定的CPU核(或CPU集合)上。进程(或线程)本质上并不与CPU核绑定。每次进程(或线程)被调度执行时,它都可以由其关联列表中的任何CPU核执行。如果未显式设置关联列表,则进程(或线程)可以在任何CPU核上运行。

      一.查看CPU信息
      1.通过命令,执行:

cat /proc/cpuinfo

      (1).processor:指明每个物理CPU中逻辑处理器信息,序号从0开始;
      (2).cpu cores: 指明每个物理CPU中总核数;
      2.查看物理CPU个数,执行:

cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l

      3.查看每个物理CPU中core的个数(即核数),执行:

cat /proc/cpuinfo | grep "cpu cores" | uniq

      4.查看逻辑CPU的个数,执行:

cat /proc/cpuinfo | grep "processor" | wc -l

      5.通过代码:sysconf函数或get_nprocs函数

void get_cpu_cores()
{
    // _SC_NPROCESSORS_CONF:系统配置的CPU核心数量
    // _SC_NPROCESSORS_ONLN:当前系统实际可用的CPU核心数量,可能会因为系统的运行状态而变化
    // 两个函数返回的值可能并不完全相同
    std::cout << "cpu cores(_SC_NPROCESSORS_CONF): " << sysconf(_SC_NPROCESSORS_CONF) << "\n";
    std::cout << "cpu cores(_SC_NPROCESSORS_ONLN): " << sysconf(_SC_NPROCESSORS_ONLN) << "\n";

    // get_nprocs_conf:系统配置的CPU核心数量; get_nprocs:当前系统中可用的CPU核心数量,此值可能小于get_nprocs_conf返回的值
    std::cout << "cpu cores(get_nprocs_conf): " << get_nprocs_conf() << "\n";
    std::cout << "cpu cores(get_nprocs): " << get_nprocs() << "\n"; 
}

      二.将进程绑定到指定的CPU核上
      1.通过taskset:(-p:pid; -c:cpu list)
      (1).查看执行程序(进程)运行在哪个CPU核上:taskset -p 进程ID(PID, 操作系统分配给每个进程的唯一标识符)
      如查看gnome-shell运行在哪个CPU核上:通过top命令查看gnome-shell的PID为1246,输入:taskset -pc 1246 ,执行结果如下图所示:

      (2).启动时指定:CPU标号从0开始,绑定多个CPU核,之间用逗号分隔
    taskset -c CPU_标号 可执行程序
      (3).启动后绑定:CPU标号从0开始,绑定多个CPU核,之间用逗号分隔
    taskset -pc CPU_标号 PID
      2.通过代码:sched_setaffinity和sched_setaffinity函数
      (1).sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask): 将ID为pid的线程的CPU亲和性掩码(CPU affinity mask)设置为mask指定的值。如果pid为0,则使用调用线程。参数cpusetsize是 mask指向的数据的长度(以字节为单位)。通常该参数被指定为sizeof(cpu_set_t)。
      (2).sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask): 将ID为pid的线程的亲和性掩码写入mask指向的cpu_set_t结构中。cpusetsize参数指定掩码的大小(以字节为单位)。如果pid为零,则返回调用线程的掩码。

void set_processor_to_cpu_core()
{

{ // sched_getaffinity
    cpu_set_t mask;
    CPU_ZERO(&mask);

    if (sched_getaffinity(0, sizeof(mask), &mask) != 0)
        std::cerr << "Error: fail to sched_getaffinity\n";

    for (auto i = 0; i < sysconf(_SC_NPROCESSORS_ONLN); ++i) {
        if (CPU_ISSET(i, &mask))
            std::cout << "CPU " << i << " is set\n";
    }
}

{ // sched_setaffinity
    cpu_set_t mask;
    CPU_ZERO(&mask);
    // 可以多次调用CPU_SET,以指定将多个CPU核添加到mask中
    CPU_SET(0, &mask); // set affinity for core 0, set the bit that represents core 0

    if (sched_setaffinity(0, sizeof(mask), &mask) != 0)
        std::cerr << "Error: fail to sched_setaffinity\n";
}

}

      三.将线程绑定到指定的CPU核上
      1.通过代码:pthread_setaffinity_np函数和pthread_getaffinity_np
      (1).pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset): 将线程thread的CPU亲和性掩码(CPU affinity mask)设置为cpuset指向的CPU集。如果调用成功,并且该线程当前未在cpuset中的某个CPU上运行,则它将迁移到这些CPU中的一个。
      (2).pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset): 获取cpuset指向的缓冲区中线程thread的CPU亲和性掩码。

void get_thread_id(int n)
{
    std::cout << "thread id: " << std::this_thread::get_id() << ", on cpu: " << sched_getcpu() << "\n";
    std::this_thread::sleep_for(std::chrono::seconds(n));
}

void set_thread_to_cpu_core()
{
    // 最大的硬件并发线程数
    std::cout << "Support concurrent threads: " << std::thread::hardware_concurrency() << "\n";
    
    std::thread th1(get_thread_id, 5), th2(get_thread_id, 5);
{ // pthread_getaffinity_np
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    
    if (pthread_getaffinity_np(th1.native_handle(), sizeof(cpuset), &cpuset) != 0)
        std::cerr << "Error: fail to pthread_getaffinity_np\n";

    // for (auto i = 0; i < sysconf(_SC_NPROCESSORS_ONLN); ++i) {
    //     if (CPU_ISSET(i, &cpuset))
    //         std::cout << "CPU " << i << " is set\n";
    // }
}

{ // pthread_setaffinity_np
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    // 可以多次调用CPU_SET,以指定将多个CPU核添加到cpuset中
    CPU_SET(0, &cpuset); // set affinity for core 0, set the bit that represents core 0

    if (pthread_setaffinity_np(th2.native_handle(), sizeof(cpuset), &cpuset) != 0)
        std::cerr << "Error: fail to pthread_setaffinity_np\n";

}

    th1.join();
    th2.join();
}

      以上测试代码执行结果如下图所示:虚拟机

Linux上将进程、线程与CPU核绑定_第1张图片

      GitHub:https://github.com/fengbingchun/Linux_Code_Test

你可能感兴趣的:(Linux,linux)