Linux编程-让进程或线程运行在指定的CPU上
<p style="text-indent: 2em;">为了让程序拥有更好的性能,有时候需要将进程或线程绑定到特定的CPU上,这样可以减少调度的开销和保护关键进程或线程。</p><p class="artical_littlestyle1">1、绑定进程到指定的CPU</p><p style="text-indent: 2em;">Linux提供一个接口,可以将进程绑定到特定的CPU:<br/><span style="color: rgb(0, 112, 192);">#include <sched.h><br/>int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *set);<br/>int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *set);</span><br/>参数:<br/>pid:进程的id号,如果pid为0,则表示本进程<br/>cpusetsize:set的大小<br/>set:运行进程的CPU,可以通过以下函数操作set:<br/><span style="color: rgb(0, 112, 192);">void CPU_ZERO(cpu_set_t *set); // Clears set, so that it contains no CPUs.<br/>void CPU_SET(int cpu, cpu_set_t *set); // Add CPU cpu to set.<br/>void CPU_CLR(int cpu, cpu_set_t *set); // Remove CPU cpu from set.<br/>int CPU_ISSET(int cpu, cpu_set_t *set); // Test to see if CPU cpu is a member of set.<br/>int CPU_COUNT(cpu_set_t * mask); //Return the number of CPUs in set.</span><br/></p><p style="text-indent: 2em;">进程绑定到指定CPU的演示程序如下:</p><pre class="brush:cpp;toolbar:false PrismJs">/*
*gcc process_test.c
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <sched.h>
void WasteTime(void)
{
int abc = 1000;
int tmp = 0;
while(abc--)
tmp = 10000*10000;
sleep(1);
}
int main(int argc, char *argv[])
{
cpu_set_t cpu_set;
while(1)
{
CPU_ZERO(&cpu_set);
CPU_SET(0, &cpu_set);
if(sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0)
perror("sched_setaffinity");
WasteTime();
CPU_ZERO(&cpu_set);
CPU_SET(1, &cpu_set);
if(sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0)
perror("sched_setaffinity");
WasteTime();
CPU_ZERO(&cpu_set);
CPU_SET(2, &cpu_set);
if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0)
perror("sched_setaffinity");
WasteTime();
CPU_ZERO(&cpu_set);
CPU_SET(3, &cpu_set);
if(sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0)
perror("sched_setaffinity");
WasteTime();
}
return 0;
}</pre><p style="text-indent: 2em;">测试:编译程序,之后运行,我编译出的文件名为a.out,执行下列命令,得到a.out的PID:<span style="color: rgb(255, 0, 0);">ps -elf | grep a.out</span>,之后输入命令:<span style="color: rgb(255, 0, 0);">top -p 进程ID</span>,接着输入f,选择P选项(移到P处,按下空格),按ESC退出,具体过程如下:</p><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.25/1535186267431668.png" onclick="preview_image('/uploads/AilsonJack/2018.08.25/1535186267431668.png')"/></p><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.25/1535186267668142.png" onclick="preview_image('/uploads/AilsonJack/2018.08.25/1535186267668142.png')"/></p><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.25/1535186270428046.png" onclick="preview_image('/uploads/AilsonJack/2018.08.25/1535186270428046.png')"/></p><p style="text-indent: 2em;">此时可以看到进程在cpu0 cpu1 cpu2 cpu3之间不停切换:</p><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.25/1535186267809476.png" onclick="preview_image('/uploads/AilsonJack/2018.08.25/1535186267809476.png')"/></p><p class="artical_littlestyle2">2、绑定线程到指定的CPU</p><p style="text-indent: 2em;">不仅仅进程可以绑定到CPU,线程也可以。Linux提供一个接口,可以将线程绑定到特定的CPU:<br/><span style="color: rgb(0, 112, 192);">#include <pthread.h><br/>int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);<br/>int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset);</span><br/></p><p style="text-indent: 2em;">该接口与进程绑定到CPU的接口的使用方法基本一致。<br/></p><p style="text-indent: 2em;">当进程绑定到特定的CPU之后,线程还是可以绑定到其他的CPU的,没有冲突。<br/></p><p style="text-indent: 2em;">示例代码如下:</p><pre class="brush:cpp;toolbar:false PrismJs">/*
*gcc thread_test.c -lpthread
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <math.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>
void WasteTime(void)
{
int abc = 1000;
int temp = 0;
while(abc--)
temp = 10000*10000;
sleep(1);
}
void *thread_func1(void *param)
{
cpu_set_t cpu_set;
while(1)
{
CPU_ZERO(&cpu_set);
CPU_SET(1, &cpu_set);
if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set),&cpu_set) < 0)
perror("pthread_setaffinity_np");
WasteTime();
CPU_ZERO(&cpu_set);
CPU_SET(2, &cpu_set);
if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set),&cpu_set) < 0)
perror("pthread_setaffinity_np");
WasteTime();
}
}
void *thread_func2(void *param)
{
cpu_set_t cpu_set;
while(1)
{
CPU_ZERO(&cpu_set);
CPU_SET(3, &cpu_set);
if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set),&cpu_set) < 0)
perror("pthread_setaffinity_np");
WasteTime();
}
}
int main(int argc, char *argv[])
{
pthread_t my_thread;
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(0, &cpu_set);
if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0)
perror("sched_setaffinity");
if (pthread_create(&my_thread, NULL, thread_func1,NULL) != 0)
perror("pthread_create");
if (pthread_create(&my_thread, NULL, thread_func2,NULL) != 0)
perror("pthread_create");
while(1)
WasteTime();
pthread_exit(NULL);
}</pre><p style="text-indent: 2em;">测试:编译程序,之后运行,我编译出的文件名为a.out,执行下列命令,得到a.out的PID:<span style="color: rgb(255, 0, 0);">ps -elf | grep a.out</span>,之后输入命令:<span style="color: rgb(255, 0, 0);">top -H -p 进程ID</span>,接着输入f,选择P选项(移到P处,按下空格)和nTH选项,按ESC退出,具体过程如下:</p><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.25/1535186269451477.png" onclick="preview_image('/uploads/AilsonJack/2018.08.25/1535186269451477.png')"/></p><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.25/1535186268210412.png" onclick="preview_image('/uploads/AilsonJack/2018.08.25/1535186268210412.png')"/></p><p style="text-align:center"><img src="/uploads/AilsonJack/2018.08.25/1535186270330139.png" onclick="preview_image('/uploads/AilsonJack/2018.08.25/1535186270330139.png')"/></p><p style="text-indent: 2em;">可以看到主线程一直保持在cpu0,一个线程在cpu1 cpu2之间切换,另一个线程一直保持在cpu3:</p><p style="text-align: center;"><img src="/uploads/AilsonJack/2018.08.25/1535186267340066.png" onclick="preview_image('/uploads/AilsonJack/2018.08.25/1535186267340066.png')"/></p>
你可能也喜欢:
暂无评论,要不要来个沙发
发表评论
JLink V9掉固件修复(灯不亮) 3Zephyr笔记2 - 在STM32F429上运行HelloWorld 2计算NandFlash要传入的行地址和列地址 1Linux MMC子系统 - 6.eMMC 5.1工作模式-设备识别模式 0Linux MMC子系统 - 5.eMMC 5.1工作模式-引导模式 0Linux MMC子系统 - 4.eMMC 5.1常用命令说明(2) 0
标签云
Linux嵌入式实用技巧ARM内核学习问题集合CC++编程语言阅读笔记汇编Linux内核完全注释Windows驱动开发计算机基础ARM11ARMv7-ASTM32IDESublimeLinux内核学习eMMCMMC子系统Ubuntu操作系统OfficeVMWareAPUEgccRTOS中断漫游世界随笔感悟开发工具软件应用编程VsCodearmccarmclang编译器ZephyrSPIJLink网卡驱动安装各种芯片库函数NFSμCOS内核sambaFlashUnix命令与脚本输入法Linux内核设计与实现gitRIFFWAVJATGFTPar8161安装centos有线上网μCGUI字库工程建立右键菜单网络文件系统Firefox百度NTFS文件系统CodeBlocksCentOS数据结构算法PhotoShop51KeilQTUltraEditscanfglibc宏定义UIDGID优先级娱乐天地SourceInsight磁盘扇区总线I2CPDFBComparePythonI2SFPUMakefileSWDCPUARP软件推荐FileZilla