让你的线程运行在不同CPU核中


Creative Commons LicenseCreative Commons LicenseCreative Commons License

当今的处理器基本都是多核的,在一些设备上对程序的性能有特殊的要求,比如减少调度的开销和保护关键进程或线程。可能需要不同进程或者线程要运行在不同的核中,本文主要是描述如何让你的线程运行在不同的CPU核上,进程运行在不同CPU核不在本文讨论范围,进程的实现可以查找关键字(sched_setaffinity)。

1 主要函数

要实现不同核上运行不同的进程和线程都是通过设置CPU亲和性(affinity)来达到目的。线程设置亲和性的接口:

1
2
3
4
5
6
7
8
9
#define _GNU_SOURCE
#include <pthread.h>
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);
pthread_setaffinity_np()函数用于设置线程亲和性掩码,通过cpuset来指定线程和CPU集
之间的亲和性,改调用成功后,如果线程没有运行在cpuset指定的核上,就会迁移改线程到cpuset指定的核中的一个。
pthread_getaffinity_np()获取线程亲和性掩码指向哪个CPU集。

2 函数返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
正确返回0,错误
EFAULT 内存地址不可用.
EINVAL (pthread_setaffinity_np()) The affinity bit mask mask contains
no processors that are currently physically on the system and
permitted to the thread according to any restrictions that may
be imposed by the "cpuset" mechanism described in cpuset(7).
EINVAL (pthread_setaffinity_np()) cpuset specified a CPU that was
outside the set supported by the kernel. (The kernel
configuration option CONFIG_NR_CPUS defines the range of the
set supported by the kernel data type used to represent CPU
sets.)
EINVAL (pthread_getaffinity_np()) cpusetsize is smaller than the size
of the affinity mask used by the kernel.
ESRCH No thread with the ID thread could be found.

3 CPU集的设置

1
2
3
4
5
6
7
8
/* 清空CPU集*/
CPU_ZERO (cpu_set_t *set); 
/* 将某个cpu加入cpu集中 */
CPU_SET (int cpu, cpu_set_t *set); 
/*将某个cpu从cpu集中移出*/
CPU_CLR (int cpu, cpu_set_t *set); 
/*判断某个cpu是否已在cpu集中设置了 */
CPU_ISSET (int cpu, const cpu_set_t *set);

4 测试程序

程序先读取cpu的核数,然后每个核创建一个线程并运行,代码下载地址
https://github.com/Jona-lee/threads_on_diffcpu/blob/master/pthread_on_cpu.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
*
* Copyright (c) 2013 javenly@gmail.com
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/

#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <sched.h>
#include <errno.h>
#include <unistd.h>

#define MAX_THREADS 8

struct thread_msg {
char name[20];
char num_of_cpu;
char run_cpu;
char start;
};

int get_cpu_num(void)
{
long nprocs = -1;
long nprocs_max = -1;

#ifdef _SC_NPROCESSORS_ONLN
nprocs = sysconf(_SC_NPROCESSORS_ONLN);
if (nprocs < 1) {
printf("Could not determine number of CPUs on line, %s\n",
strerror(errno));
return 0;
}
nprocs_max = sysconf(_SC_NPROCESSORS_CONF);
if (nprocs_max < 1) {
printf("Could not determine number of CPUs in host, %s\n",
strerror(errno));
return 0;
}
printf("%d of %d CPUs online\n", nprocs, nprocs_max);
return nprocs;
#else
printf("Could not determine number of CPUs\n");
return 0;
#endif
}

void *pthread_handle( void *ptr )
{
struct thread_msg *msg = (struct thread_msg *)ptr;
cpu_set_t cpuset;
int maxcpus;
int i;

while(!msg->start)
usleep(10000);

CPU_ZERO(&cpuset);

if (pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) == 0)
for (i = 0; i < msg->num_of_cpu; i++)
if (CPU_ISSET(i, &cpuset))
printf("%s(ID:%u) : CPU %d\n", msg->name, pthread_self(), i);
while(1) {
//do something here.
sleep(1);
}
}

int main()
{
pthread_t thread[MAX_THREADS];
struct thread_msg tmsg[MAX_THREADS];
cpu_set_t cpuset[MAX_THREADS];
int num, ret, i;

num = get_cpu_num();
if (num > MAX_THREADS)
num = MAX_THREADS;

for (i = 0; i < num; i++) {
snprintf(tmsg[i].name, sizeof(tmsg[i].name), "thread %d", i);
tmsg[i].num_of_cpu = num;
tmsg[i].run_cpu = i;
tmsg[i].start = 0;
ret = pthread_create(&thread[i], NULL, &pthread_handle, (void*)&tmsg[i]);
if (ret != 0) {
printf("can not creat thread %d, %s\n", i, strerror(errno));
break;
}

CPU_ZERO(&cpuset[i]);
CPU_SET(i, &cpuset[i]);
ret = pthread_setaffinity_np(thread[i], sizeof(cpu_set_t), &cpuset[i]);
if (ret != 0) {
printf("can not set thread %d affinity, %s\n", i, strerror(errno));
break;
}
tmsg[i].start = 1;
usleep(100000);
}

for (i = 0; i < num; i++) {
pthread_join(thread[i], NULL);
}

return 0;
}
-------------本文结束感谢您的阅读-------------
如果文章对您有帮助,也可以打赏支持喔!