Linux 中用c++实现线程绑定CPU

简介: Linux 中用c++实现线程绑定CPU

前言

嵌入式里面我们会使用到多核的cpu,随着产品芯片性能提升,我们也会有很多功能,以及很多进程产生运行,这个时候我们在任务调度调优的时候,把一些进程绑定到固定cpu运行,下面就来分享一下cpu绑定运行的过程:

首先运行的环境需要多核,大家可以按照下面命令进行查询对应设备的cpu数量

查看cpu有几个核

使用cat /proc/cpuinfo查看cpu信息,如下两个信息:

processor,指明第几个cpu处理器

cpu cores,指明每个处理器的核心数

839886cd3c004deb9abdba851aa48a4c.png

基本概念

cpu亲和性(affinity)

CPU的亲和性, 就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器,也称为CPU关联性;再简单的点的描述就将指定的进程或线程绑定到相应的cpu上;在多核运行的机器上,每个CPU本身自己会有缓存,缓存着进程使用的信息,而进程可能会被OS调度到其他CPU上,如此,CPU cache命中率就低了,当绑定CPU后,程序就会一直在指定的cpu跑,不会由操作系统调度到其他CPU上,性能有一定的提高。

软亲和性(affinity)

就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器,Linux 内核进程调度器天生就具有被称为 软 CPU 亲和性(affinity) 的特性,这意味着进程通常不会在处理器之间频繁迁移。这种状态正是我们希望的,因为进程迁移的频率小就意味着产生的负载小。

硬亲和性(affinity)

简单来说就是利用linux内核提供给用户的API,强行将进程或者线程绑定到某一个指定的cpu核运行。


代码绑定实现

上面我们使用cat /proc/cpuinfo命令查询了自己设备的CPU,以我为例,我的电脑从0~7一共有8核。

下面是代码的demo:

#include <stdio.h>
#include <unistd.h>
#include <thread>
void thread_func1()
{
        cpu_set_t mask;
        CPU_ZERO(&mask);
        CPU_SET(1, &mask); //指定该线程使用的CPU
        if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0) {
                perror("pthread_setaffinity_np");
        }
        int count = 0;
        while(1)
        {
                count ++;
                sleep(1);
                printf("fun 1 cnt :%d \n",count);
                for(int i = 0; i < 8; i++) {
                        if (CPU_ISSET(i, &mask))  //查看cpu i 是否在get 集合当中
                        {
                                printf("1 this process %d of running processor: %d\n", getpid(), i);
                        }
                }
        }
}
void thread_func2()
{
        int count = 0;
        cpu_set_t mask;
        CPU_ZERO(&mask);
        CPU_SET(5, &mask);
        if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0) {
                perror("pthread_setaffinity_np");
        }
        while(1)
        {
                usleep(1000*1000);
                count ++;
                printf("fun 2 cnt :%d \n",count);
                for(int i = 0; i < 8; i++) {
                 if (CPU_ISSET(i, &mask))  //查看cpu i 是否在get 集合当中
                {
                       printf("2 this process %d of running processor: %d\n", getpid(), i);
                    }
                }
        }
}
int main(int argc, char *argv[])
{
      int cpus = 0;
        cpus = sysconf(_SC_NPROCESSORS_CONF);
        printf("cpus: %d\n", cpus); //查看cpu的个数;
    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(7, &mask);
    if (sched_setaffinity(0, sizeof(mask), &mask) < 0) {
        perror("sched_setaffinity");
    }
    std::thread t1(thread_func1);
    std::thread t2(thread_func2);
        usleep(1000); /* 让当前的设置有足够时间生效*/
       while(1)
        {
                /*查看运行在当前进程的cpu*/
                sleep(1); /* 让当前的设置有足够时间生效*/
                printf("fun main \n");
                for(int i = 0; i < cpus; i++) {
                        if (CPU_ISSET(i, &mask))  //查看cpu i 是否在get 集合当中
                        {
                                printf("3 this process %d of running processor: %d\n", getpid(), i);
                        }
                }
        }
    t1.join();
    t2.join();
}

使用此命令编译:

g++ test_select_cpu.cpp -pthread --std=c++11

上面一共运行了三个线程,一个是main 主线程,还有两个是自己定义的thread。

最重要的设置代码就是下面所示:设置cpu 亲和

cpu_set_t mask;
CPU_ZERO(&mask);/* 初始化set集,将set置为空*/
CPU_SET(5, &mask);/* 将对应的cpu序号加入到集合*/
if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0) /*设置cpu 亲和性(affinity)*/
{ 
    perror("pthread_setaffinity_np");
}

执行代码 ./a.out

839886cd3c004deb9abdba851aa48a4c.png


代码绑定查看

使用ps -ef | grep a.out 命令查看对应的PID

839886cd3c004deb9abdba851aa48a4c.png

使用 top命令查看对应pid的线程详细信息 top -p 54056

839886cd3c004deb9abdba851aa48a4c.png

在进入top命令后,继续输入 f

839886cd3c004deb9abdba851aa48a4c.png

使用上下 移动高亮到p

839886cd3c004deb9abdba851aa48a4c.png

空格 选中

839886cd3c004deb9abdba851aa48a4c.png

再按q 退出显示

839886cd3c004deb9abdba851aa48a4c.png

输入大写H

就可以看到对应线程数据了

839886cd3c004deb9abdba851aa48a4c.png

最右边就是对应的线程绑定的CPU序号。


作者:良知犹存,白天努力工作,晚上原创公号号主。公众号内容除了技术还有些人生感悟,一个认真输出内容的职场老司机,也是一个技术之外丰富生活的人,摄影、音乐 and 篮球。关注我,与我一起同行。

目录
相关文章
|
14天前
|
存储 Linux API
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
|
5月前
|
存储 Linux C语言
Linux C/C++之IO多路复用(aio)
这篇文章介绍了Linux中IO多路复用技术epoll和异步IO技术aio的区别、执行过程、编程模型以及具体的编程实现方式。
201 1
Linux C/C++之IO多路复用(aio)
|
1月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
48 17
|
1月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
59 26
|
1月前
|
消息中间件 Linux C++
c++ linux通过实现独立进程之间的通信和传递字符串 demo
的进程间通信机制,适用于父子进程之间的数据传输。希望本文能帮助您更好地理解和应用Linux管道,提升开发效率。 在实际开发中,除了管道,还可以根据具体需求选择消息队列、共享内存、套接字等其他进程间通信方
65 16
|
2月前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
70 13
|
5月前
|
Ubuntu Linux 编译器
Linux/Ubuntu下使用VS Code配置C/C++项目环境调用OpenCV
通过以上步骤,您已经成功在Ubuntu系统下的VS Code中配置了C/C++项目环境,并能够调用OpenCV库进行开发。请确保每一步都按照您的系统实际情况进行适当调整。
1102 3
|
5月前
|
资源调度 Linux 调度
Linux C/C++之线程基础
这篇文章详细介绍了Linux下C/C++线程的基本概念、创建和管理线程的方法,以及线程同步的各种机制,并通过实例代码展示了线程同步技术的应用。
74 0
Linux C/C++之线程基础
|
5月前
|
Linux C++
Linux C/C++之IO多路复用(poll,epoll)
这篇文章详细介绍了Linux下C/C++编程中IO多路复用的两种机制:poll和epoll,包括它们的比较、编程模型、函数原型以及如何使用这些机制实现服务器端和客户端之间的多个连接。
112 0
Linux C/C++之IO多路复用(poll,epoll)
|
5月前
|
C++
C++ 20新特性之结构化绑定
在C++ 20出现之前,当我们需要访问一个结构体或类的多个成员时,通常使用.或->操作符。对于复杂的数据结构,这种访问方式往往会显得冗长,也难以理解。C++ 20中引入的结构化绑定允许我们直接从一个聚合类型(比如:tuple、struct、class等)中提取出多个成员,并为它们分别命名。这一特性大大简化了对复杂数据结构的访问方式,使代码更加清晰、易读。
74 0