博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
posix多线程有感--线程高级编程(均衡负载CPU绑定)
阅读量:5934 次
发布时间:2019-06-19

本文共 5785 字,大约阅读时间需要 19 分钟。

        多线程、多进程的情况下。可以同过指定CPU进行负载均衡,而不是让操作系统自动进行负载均衡。因为你比操作系统更了解自己的程序,为了避免调度器愚蠢的调度你的程序,或是为了在多线程程序中避免缓存失效造成的开销。

        将进程/线程与cpu绑定,最直观的好处就是提高了cpu cache的命中率,从而减少内存访问损耗,提高程序的速度。我觉得在NUMA架构下,这个操作对系统运行速度的提升有较大的意义,而在SMP架构下,这个提升可能就比较小。这主要是因为两者对于cache、总线这些资源的分配使用方式不同造成的,NUMA每个cpu有自己的一套资源体系, SMP中每个核心还是需要共享这些资源的,从这个角度来看,NUMA使用cpu绑定时,每个核心可以更专注地处理一件事情,资源体系被充分使用,减少了同步的损耗。SMP由于一部分资源的共享,在进行了绑定操作后,受到的影响还是很大的。

通过linux提供的几个api,可以轻松地完成这个优化:

#define _GNU_SOURCE             #include 
int sched_setaffinity(pid_t pid, size_t cpusetsize,cpu_set_t *mask); //设定pid 绑定的cpu, int sched_getaffinity(pid_t pid, size_t cpusetsize,cpu_set_t *mask); //查看pid 绑定的cpu。
cpu_set_t  //是一个掩码数组,一共有1024位,每一位都可以对应一个cpu核心//以下宏,都是对这个掩码进行操作的。如果需要,一个进程是可以绑定多个cpu的。void CPU_ZERO(cpu_set_t *set);void CPU_SET(int cpu, cpu_set_t *set);void CPU_CLR(int cpu, cpu_set_t *set);int CPU_ISSET(int cpu, cpu_set_t *set);

      函数中pid表示需要设置或获取绑定信息的线程id(或进程id),如果为0,表示对当前调用的线程进行设置;第2个参数cpusetsize一般设置为sizeof(cpu_set_t),用以表示第3个参数指向的内存结构对象的大小;第3个参数mask指向类型为cpu_set_t对象的指针,用以设置或获取指定线程可以使用的CPU核列表。Linux提供函数CPU_ZERO、CPU_SET和CPU_ISSET对cpu_set_t类型的对象进行操作,其中CPU_ZERO用于清空cpu_set_t类型对象的内容,CPU_SET用于设置cpu_set_t类型对象,CPU_ISSET用于判断cpu_set_t类型对象与核对应的位是否被设置。

下面是一个实例。

#include 
#include
#include
#define __USE_GNU //启用CPU_ZERO等相关的宏//#define _GNU_SOURCE#include
#include
//这个东西原来放在__USE_GNU宏之前,结果被编译器报错说CPU_ZERO未定义void* new_test_thread(void* arg){ cpu_set_t mask; int i = 0; int num = sysconf(_SC_NPROCESSORS_CONF); //获取当前的cpu总数 pthread_detach(pthread_self()); CPU_ZERO(&mask); CPU_SET(1, &mask); //绑定cpu 1 if(sched_setaffinity(0, sizeof(mask), &mask) == -1) //0 代表对当前线程/进程进行设置。 { printf("set affinity failed.."); } while(1) { CPU_ZERO(&mask); if(sched_getaffinity(0, sizeof(mask), &mask) == -1) { printf("get failed..\n"); } for(i = 0; i < num; i++) { if(CPU_ISSET(i, &mask)) printf("new thread %d run on processor %d\n", getpid(), i); } while(1); sleep (1); }} //while(1); //如果觉得不明显,改成这个,void* child_test_thread(void* arg){ cpu_set_t mask; int i = 0; int num = sysconf(_SC_NPROCESSORS_CONF); pthread_detach(pthread_self()); while(1) { CPU_ZERO(&mask); if(sched_getaffinity(0, sizeof(mask), &mask) == -1) { printf("get failed..\n"); } for(i = 0; i < num; i++) { if(CPU_ISSET(i, &mask)) printf("child thread %d run on processor %d\n", getpid(), i); } sleep (1); }}intmain(int argc, char* argv[]){ int num = sysconf(_SC_NPROCESSORS_CONF); int created_thread = 0; int myid; int i; int j = 0; pthread_t ptid = 0; cpu_set_t mask; cpu_set_t get; if(argc != 2) { printf("usage: ./cpu num\n"); return -1; } myid = atoi(argv[1]); printf("system has %i processor(s).\n", num); CPU_ZERO(&mask); CPU_SET(myid, &mask); if(sched_setaffinity(0, sizeof(mask), &mask) == -1) { printf("warning: set CPU affinity failed..."); } int ret = pthread_create(&ptid, NULL, new_test_thread, NULL); if(ret) { return -1; } ret = pthread_create(&ptid, NULL, child_test_thread, NULL); if(ret) { return -1; } while(1) { CPU_ZERO(&get); if(sched_getaffinity(0, sizeof(get), &get) == -1) { printf("can't get cpu affinity..."); } for(i = 0; i < num; i++) { if(CPU_ISSET(i, &get)) { printf("this process %d is runing on procesor:%d\n", getpid(), i); } } sleep(1); } //while(1); //使用这个更明显 return 0;}

执行./cpu ,使用top观察cpu使用状况。 使用./cpu 0 时,可以发现,两颗核心使用率都比较高, 使用./cpu 1时,可以发现,1核的压力比较重。

特别注意:

#define __USE_GNU不要写成#define _USE_GNU

#include<pthread.h>必须写在#define __USE_GNU之后,否则编译会报错

查看你的线程情况可以在执行时在另一个窗口使用top -H来查看线程的情况,查看各个核上的情况请使用top命令然后按数字“1”来查看。

 

当然还可以对线程进行cpu绑定。

[cpp]
  1. #define _GNU_SOURCE   
  2. #include <pthread.h>   
  3.    
  4. int pthread_setaffinity_np(pthread_t threadsize_t cpusetsize,  
  5.                           const cpu_set_t *cpuset);  
  6. int pthread_getaffinity_np(pthread_t threadsize_t cpusetsize,  
  7.                           cpu_set_t *cpuset);  
int bind2cpu(int cpu_index){	cpu_set_t set;	cpu_set_t get;	int cpu_num = sysconf(_SC_NPROCESSORS_CONF);	if(cpu_index >= cpu_num)		return -1;	CPU_ZERO(&set);	CPU_SET(cpu_index, &set);	if (pthread_setaffinity_np(pthread_self(), sizeof(set), &set) < 0) {		perror( "set thread affinity failed");		return -2;	}#if 1	CPU_ZERO(&get);	if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) < 0) {		perror("get thread affinity failed");		return -3;	}	int j;		for (j = 0; j < cpu_num; j++) {		if (CPU_ISSET(j, &get)) {			printf("the thread is running in processor %d\n", j);		}	}#endif	return 0;}

 

这个介绍了使用的时机,比较经典:http://www.ibm.com/developerworks/cn/linux/l-affinity.html

 

进程/线程指定函数:sched_setaffinity(); sched_getaffinity();
线程指定函数:pthread_setaffinity_np(); pthread_getaffinity_np();
 
//#define __USE_GNU#define _GNU_SOURCE#include 
#include
#include
#include
#include
int main(int argc, char **argv){ int i = 0; int setid = 0; int prcs_num = 0; cpu_set_t mask; if (argc == 2) setid = atoi(argv[1]); prcs_num = sysconf(_SC_NPROCESSORS_CONF); printf("System has %d processor(s).\n", prcs_num); CPU_ZERO(&mask); CPU_SET(setid, &mask); if (-1 == sched_setaffinity(0, sizeof(mask), &mask)) { perror("sched_setaffinity"); exit(-1); } CPU_ZERO(&mask); if (-1 == sched_getaffinity(0, sizeof(mask), &mask)) { perror("sched_getaffinity"); exit(-1); } for (i = 0; i < prcs_num; ++i) if (CPU_ISSET(i, &mask)) printf("The process %d is running in processor %d\n", getpid(), i); exit(0);}

转载于:https://www.cnblogs.com/hehehaha/archive/2013/05/10/6332827.html

你可能感兴趣的文章
由浅入深学习Apache httpd原理与配置
查看>>
用tiny project来激励自己入门
查看>>
制作同时支持armv7,armv7s,arm64,i386,x86_64的静态库.a
查看>>
Beyond Compare的几种实用功能
查看>>
旧工程适配iOS 6和iPhone 5的一些故事
查看>>
CentOS版本怎么安装python的pip及mycli的安装
查看>>
was安装
查看>>
Android Studio 使用艺术
查看>>
Android架构:第四部分-在Android上应用Clean架构,实践(包含源代码)(译)
查看>>
Jenkins打包参数输入多个Cherry-Pick
查看>>
java文件下载(二)
查看>>
查找目录中包含指定关键字的文件
查看>>
XCode升级后插件不能使用之VVDocument
查看>>
好东西推荐,不说了直接看吧
查看>>
ELK -- Logstash安装与配置
查看>>
关于CSS中的float和position和z-index
查看>>
奇淫巧技
查看>>
teamlog 开源项目详细介绍 - 源代码使用篇
查看>>
[react-native]-开发环境搭建for Mac OSX
查看>>
SVN搭建指南
查看>>