===============================================================
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
thread
,
size_t
cpusetsize,
const
cpu_set_t *cpuset);
int
pthread_getaffinity_np(pthread_t
thread
,
size_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五個核
- #define _GNU_SOURCE
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <sched.h>
- inline int set_cpu(int i)
- {
- cpu_set_t mask;
- CPU_ZERO(&mask);
- CPU_SET(i,&mask);
- printf("thread %u, i = %d\n", pthread_self(), i);
- if(-1 == pthread_setaffinity_np(pthread_self() ,sizeof(mask),&mask))
- {
- fprintf(stderr, "pthread_setaffinity_np erro\n");
- return -1;
- }
- return 0;
- }
- void *thread_ip_bitmap_set(void *p)
- {
- uint32_t i, ip;
- struct id_ipmap *entry;
- thread_info_t *info = (thread_info_t *)p;
- if(set_cpu(info->id))
- {
- return NULL;
- }
- printf("info->id = %d; info->start = %d; info->end = %d, sub = %d\n", info->id, info->start, info->end, info->start - info->end);
- for (i = info->start; i < info->end; ++i) {
- entry = &ipmap_queue[i];
- for (ip = entry->ip_start; ip < entry->ip_end; ip++) {
- ip_bitmap_set(adns_htobe32(ip), entry->id);
- }
- }
- printf("info->id = %d finished\n", info->id);
- return NULL;
- }
- int main()
- {
- for(thread_index=0; thread_index < 10; thread_index++)
- pthread_create(&thread_id[thread_index],NULL, thread_ip_bitmap_set, &thread_info[thread_index]);
- }
- #define _GNU_SOURCE
- #include <sched.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include<string.h>
- #include <stdio.h>
- #include <errno.h>
- #include <pthread.h>
- inline int set_cpu(int i)
- {
- cpu_set_t mask;
- CPU_ZERO(&mask);
- CPU_SET(i,&mask);
- printf("thread %u, i = %d\n", pthread_self(), i);
- if(-1 == pthread_setaffinity_np(pthread_self() ,sizeof(mask),&mask))
- {
- return -1;
- }
- return 0;
- }
- void *fun(void *i)
- {
- if(set_cpu(*(int *)i))
- {
- printf("set cpu erro\n");
- }
- long long a = 0;
- while(1)
- {
- a += rand();
- }
- return NULL;
- }
- int main (int argc, const char * argv[]) {
- int i;
- int cpu_nums = sysconf(_SC_NPROCESSORS_CONF);
- printf("cpu_numbs = %d\n", cpu_nums);
- pthread_t Thread[10];
- int tmp[10];
- for(i = 0; i < 10; ++i)
- {
- tmp[i] = i;
- pthread_create(&Thread[i],NULL,fun, &tmp[i]);
- }
- for(i = 0; i < 10; ++i)
- {
- pthread_join(Thread[i],NULL);
- }
- return 0;
- }
轉載: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系統調用
問題描述
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用戶指定的進程。