linux下将不同线程绑定到不同core和cpu上——pthread_setaffinity_np

===============================================================

linux下的单进程多线程的程序,要实现每个线程平均分配到多核cpu,主要有2个方法

1:利用linux系统自己的线程切换机制,linux有一个服务叫做irqbalance,这个服务是linux系统自带的,默认会启动,这个服务的作用就是把多线程平均分配到CPU的每个核上面,只要这个服务不停止,多线程分配就可以自己实现。但是要注意,如果线程函数内部的有某个循环,且该循环内没有任何系统调用的话,可能会导致这个线程的CPU时间无法被切换出去。也就是占满CPU现象,此时加个系统调用,例如sleep,线程所占的CPU时间就可以切换出去了。

2:利用pthread库自带的线程亲和性设置函数,来设置线程在某个CPU核心上跑,这个需要在程序内部实现。同时注意不要和进程亲和性设置搞混淆了


1

2

3

4

5

6

7

8

9

10

11

12

13

int pthread_setaffinity_np(pthread_t threadsize_t cpusetsize,

const cpu_set_t *cpuset);

int pthread_getaffinity_np(pthread_t threadsize_t cpusetsize, 

cpu_set_t *cpuset);

从函数名以及参数名都很明了,唯一需要点解释下的可能就是cpu_set_t这个结构体了。这个结构体的理解类似于select中的fd_set,可以理解为cpu集,也是通过约定好的宏来进行清除、设置以及判断:

//初始化,设为空

void CPU_ZERO (cpu_set_t *set); 

//将某个cpu加入cpu集中 

void CPU_SET (int cpu, cpu_set_t *set); 

//将某个cpu从cpu集中移出 

void CPU_CLR (int cpu, cpu_set_t *set); 

//判断某个cpu是否已在cpu集中设置了 

int CPU_ISSET (int cpu, const cpu_set_t *set);

=================================================================

转自:http://blog.csdn.net/sprintfwater/article/details/39203049

将线程绑定到不同的processor上:

这里加入有两个cpu,一个cpu五个核

[html] view plain copy

print?

  1. #define _GNU_SOURCE
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <stdint.h>
  6. #include <sched.h>
  7. inline int set_cpu(int i)
  8. {
  9. cpu_set_t mask;
  10. CPU_ZERO(&mask);
  11. CPU_SET(i,&mask);
  12. printf("thread %u, i = %d\n", pthread_self(), i);
  13. if(-1 == pthread_setaffinity_np(pthread_self() ,sizeof(mask),&mask))
  14. {
  15. fprintf(stderr, "pthread_setaffinity_np erro\n");
  16. return -1;
  17. }
  18. return 0;
  19. }
  20. void *thread_ip_bitmap_set(void *p)
  21. {
  22. uint32_t i, ip;
  23. struct id_ipmap *entry;
  24. thread_info_t *info = (thread_info_t *)p;
  25. if(set_cpu(info->id))
  26. {
  27. return NULL;
  28. }
  29. printf("info->id = %d; info->start = %d;  info->end = %d, sub = %d\n", info->id, info->start, info->end, info->start - info->end);
  30. for (i = info->start; i < info->end; ++i) {
  31. entry = &ipmap_queue[i];
  32. for (ip = entry->ip_start; ip < entry->ip_end; ip++) {
  33. ip_bitmap_set(adns_htobe32(ip), entry->id);
  34. }
  35. }
  36. printf("info->id = %d finished\n", info->id);
  37. return NULL;
  38. }
  39. int main()
  40. {
  41. for(thread_index=0; thread_index < 10; thread_index++)
  42. pthread_create(&thread_id[thread_index],NULL, thread_ip_bitmap_set, &thread_info[thread_index]);
  43. }

[cpp] view plain copy

print?

  1. #define _GNU_SOURCE
  2. #include <sched.h>
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include<string.h>
  6. #include <stdio.h>
  7. #include <errno.h>
  8. #include <pthread.h>
  9. inline int set_cpu(int i)
  10. {
  11. cpu_set_t mask;
  12. CPU_ZERO(&mask);
  13. CPU_SET(i,&mask);
  14. printf("thread %u, i = %d\n", pthread_self(), i);
  15. if(-1 == pthread_setaffinity_np(pthread_self() ,sizeof(mask),&mask))
  16. {
  17. return -1;
  18. }
  19. return 0;
  20. }
  21. void *fun(void *i)
  22. {
  23. if(set_cpu(*(int *)i))
  24. {
  25. printf("set cpu erro\n");
  26. }
  27. long long a = 0;
  28. while(1)
  29. {
  30. a += rand();
  31. }
  32. return NULL;
  33. }
  34. int main (int argc, const char * argv[]) {
  35. int i;
  36. int cpu_nums = sysconf(_SC_NPROCESSORS_CONF);
  37. printf("cpu_numbs = %d\n", cpu_nums);
  38. pthread_t Thread[10];
  39. int tmp[10];
  40. for(i = 0; i < 10; ++i)
  41. {
  42. tmp[i] = i;
  43. pthread_create(&Thread[i],NULL,fun, &tmp[i]);
  44. }
  45. for(i = 0; i < 10; ++i)
  46. {
  47. pthread_join(Thread[i],NULL);
  48. }
  49. return 0;
  50. }

转载:http://blog.csdn.net/xluren/article/details/43202201

coolshell最新的文章《性能调优攻略》在“多核CPU调优”章节,提到“我们不能任由操作系统负载均衡,因为我们自己更了解自己的程序,所以,我们可以手动地为其分配CPU核,而不会过多地占用CPU0,或是让我们关键进程和一堆别的进程挤在一起。”。在文章中提到了Linux下的一个工具,taskset,可以设定单个进程运行的CPU。

同时,因为最近在看redis的相关资料,redis作为单进程模型的程序,为了充分利用多核CPU,常常在一台server上会启动多个实例。而为了减少切换的开销,有必要为每个实例指定其所运行的CPU。

下文,将会介绍taskset命令,以及sched_setaffinity系统调用,两者均可以指定进程运行的CPU实例。

1.taskset

taskset是LINUX提供的一个命令(ubuntu系统可能需要自行安装,schedutils package)。他可以让某个程序运行在某个(或)某些CPU上。

以下均以redis-server举例。

1)显示进程运行的CPU

命令taskset -p 21184

显示结果:

pid 21184‘s current affinity mask: ffffff

注:21184是redis-server运行的pid

显示结果的ffffff实际上是二进制24个低位均为1的bitmask,每一个1对应于1个CPU,表示该进程在24个CPU上运行

2)指定进程运行在某个特定的CPU上

命令taskset -pc 3 21184

显示结果:

pid 21184‘s current affinity list: 0-23
pid 21184‘s new affinity list: 3

注:3表示CPU将只会运行在第4个CPU上(从0开始计数)。

3)进程启动时指定CPU

命令taskset -c 1 ./redis-server ../redis.conf

结合这上边三个例子,再看下taskset的manual,就比较清楚了。

OPTIONS
-p, --pid
operate on an existing PID and not launch a new task

-c, --cpu-list
specify a numerical list of processors instead of a bitmask. The list may contain multiple items, separated by comma, and ranges. For example, 0,5,7,9-11.

2.sched_setaffinity系统调用

如下文章部分翻译自:http://www.thinkingparallel.com/2006/08/18/more-information-on-pthread_setaffinity_np-and-sched_setaffinity/

问题描述

sched_setaffinity可以将某个进程绑定到一个特定的CPU。你比操作系统更了解自己的程序,为了避免调度器愚蠢的调度你的程序,或是为了在多线程程序中避免缓存失效造成的开销,你可能会希望这样做。如下是sched_setaffinity的例子,其函数手册可以参考(http://www.linuxmanpages.com/man2/sched_getaffinity.2.php):

 1 /* Short test program to test sched_setaffinity
 2 * (which sets the affinity of processes to processors).
 3 * Compile: gcc sched_setaffinity_test.c
 4 *              -o sched_setaffinity_test -lm
 5 * Usage: ./sched_setaffinity_test
 6 *
 7 * Open a "top"-window at the same time and see all the work
 8 * being done on CPU 0 first and after a short wait on CPU 1.
 9 * Repeat with different numbers to make sure, it is not a
10 * coincidence.
11 */
12  
13 #include <stdio.h>
14 #include <math.h>
15 #include <sched.h>
16  
17 double waste_time(long n)
18 {
19     double res = 0;
20     long i = 0;
21     while(i <n * 200000) {
22         i++;
23         res += sqrt (i);
24     }
25     return res;
26 }
27  
28 int main(int argc, char **argv)
29 {
30     unsigned long mask = 1; /* processor 0 */
31  
32     /* bind process to processor 0 */
33     if (sched_setaffinity(0, sizeof(mask), &mask) <0) {
34         perror("sched_setaffinity");
35     }
36  
37     /* waste some time so the work is visible with "top" */
38     printf ("result: %f\n", waste_time (2000));
39  
40     mask = 2; /* process switches to processor 1 now */
41     if (sched_setaffinity(0, sizeof(mask), &mask) <0) {
42         perror("sched_setaffinity");
43     }
44  
45     /* waste some more time to see the processor switch */
46     printf ("result: %f\n", waste_time (2000));
47 }

根据你CPU的快慢,调整waste_time的参数。然后使用top命令,就可以看到进程在不同CPU之间的切换。(启动top命令后按“1”,可以看到各个CPU的情况)。

父进程和子进程之间会继承对affinity的设置。因此,大胆猜测,taskset实际上是首先执行了sched_setaffinity系统调用,然后fork+exec用户指定的进程。

时间: 2024-08-02 19:16:12

linux下将不同线程绑定到不同core和cpu上——pthread_setaffinity_np的相关文章

Linux下监听或绑定(bind)21端口失败

问题:写了一个程序,尝试在21端口监听,结果在执行bind的时候失败了. sockaddr_in sock_addr; sock_addr.sin_family = AF_INET; sock_addr.sin_addr.s_addr = host_inet_addr; sock_addr.sin_port = htons(port);    //port=21 ret = bind( m_socket_fd, (const sockaddr*)&sock_addr, sizeof(sockad

LINUX下的简单线程池

前言 任何一种设计方式的引入都会带来额外的开支,是否使用,取决于能带来多大的好处和能带来多大的坏处,好处与坏处包括程序的性能.代码的可读性.代码的可维护性.程序的开发效率等. 线程池适用场合:任务比较多,需要拉起大量线程来处理:任务的处理时间相对比较短,按照线程的周期T1(创建阶段).T2(执行阶段).T3(销毁阶段)来算,执行阶段仅占用较少时间. 简单的线程池通常有以下功能:预创建一定数量的线程:管理线程任务,当工作线程没有事情可做时休眠自己:销毁线程池. 复杂一些的线程池有额外的调节功能:管

Linux 下进程与线程的基本概念

2019-10-01 关键字:进程.线程.信号量.互斥锁 什么是程序? 程序就是存放在磁盘上的指令和数据的有序集合,就是源代码编译产物. 它是静态的. 什么是进程? 进程就是操作系统为执行某个程序所分配的资源的总称.进程是程序的一次执行过程,因此它与程序不同,它是动态的.它的生命周期包括创建.调度.执行和消亡. 进程的内容主要包括以下三个部分: 1.正文段: 2.用户数据段: 3.系统数据段. 其中正文段与用户数据段两部分是从程序当中来的.而系统数据段则是操作系统分配的用来管理这个进程用的. 系

linux 将进程或者线程绑定到指定的cpu上

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

在Linux下写一个线程池以及线程池的一些用法和注意点

-->线程池介绍(大部分来自网络)  在这个部分,详细的介绍一下线程池的作用以及它的技术背景以及他提供的一些服务等.大部分内容来自我日常生活中在网络中学习到的一些概念性的东西. -->代码(大约240行)  测试一下,具体的实现. -->代码下载 --------------------------------------------------------------------------------------------------------------------------

Linux下C的线程同步机制

C里提供了保证线程安全性的三种方法: (添加头文件#include<pthread.h>,pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a, 在编译中要加 -lpthread参数) 互斥锁 通过锁的机制实现线程间的互斥,同一时刻只有一个线程可以锁定它,当一个锁被某个线程锁定的时候,如果有另外一个线程尝试锁定这个临界区(互斥体),则第二个线程会被阻塞,或者说被置于等待状态.只有当第一个线程释放了对临界区的锁定,第二个线程才能从阻塞状态恢复运行. i

linux下如何将sheduler绑定到制定的cpu核上

作者:张昌昌 1.顺序绑定 erl +sbt db 是按从前到后的顺序来绑定调度器的,如: erl +sbt db +S 3含义是启动erlang虚拟机,开启3个调度器,按顺序绑定在0,1,2号核上. 2.随机绑定 利用taskset命令, taskset -c 1,3,5 erl +S 3:含义是启动3个调度器的erlang虚拟机,3个调度器分别绑定在指定的1,3,5号cpu核上,然后可执行 top命令,按下1查看各核的负载情况. taskset -c 1-5 erl +S 5:含义是启动5个

Linux下多线程1——线程相关函数

多线程一些基本函数与标识符 (1)pthread_t  : unsigned long int 是一个线程标识符 (2)pthread_create 创建线程的函数 int pthread_create(pthread_t *_thread, //第一个参数指向线程标识符的指针 __const pthread_attr_t *__attr  //第二个参数是线程属性 void *(*__start_routine) (void *)//线程运行函数的起始地址 void *__arg  //线程函

Linux下进程与线程的区别及查询方法

在平时工作中,经常会听到应用程序的进程和线程的概念,那么它们两个之间究竟有什么关系或不同呢?一.深入理解进程和线程的区别 1)两者概念 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程是指进程内的一个执行单元,也是进程内的可调度实体. 线程是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位线程自己基本上不拥有系统资源,只拥有一点 在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线