可是如何查看线程的CPU呢?top
-Hp pid,pid就是你当前程序的进程号,如果是多线程的话,是可以查看进程内所有线程的CPU和内存使用情况。
pstree可以查看主次线程,同样的pstree -p pid。可以查看进程的线程情况。
taskset这个其实才是重点,可以查看以及设置当前进程或线程运行的CPU(设置亲和力)。
taskset -pc pid,查看当前进程的cpu,当然有的时候不只是一个,taskset -pc cpu_num pid ,cpu_num就是设置的cpu。
这样的话基本的命令和 *** 作其实大家都知道了,接下来就是在代码中完成这些 *** 作,并通过命令去验证代码的成功率。
进程制定CPU运行:
[cpp] view plain copy
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/sysinfo.h>
#include<unistd.h>
#define __USE_GNU
#include<sched.h>
#include<ctype.h>
#include<string.h>
int main(int argc, char* argv[])
{
//sysconf获取有几个CPU
int num = sysconf(_SC_NPROCESSORS_CONF)
int created_thread = 0
int myid
int i
int j = 0
//原理其实很简单,就是通过cpu_set_t进行位与 *** 作
cpu_set_t mask
cpu_set_t get
if (argc != 2)
{
printf("usage : ./cpu num\n")
exit(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: could not set CPU affinity, continuing...\n")
}
while (1)
{
CPU_ZERO(&get)
//获取当前进程的亲和力
if (sched_getaffinity(0, sizeof(get), &get) == -1)
{
printf("warning: cound not get cpu affinity, continuing...\n")
}
for (i = 0i <numi++)
{
if (CPU_ISSET(i, &get))
{
printf("this process %d is running processor : %d\n",getpid(), i)
}
}
}
return 0
}
进程设置CPU运行,其实只能是单线程。多线程设定CPU如下:
[cpp] view plain copy
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
void *myfun(void *arg)
{
cpu_set_t mask
cpu_set_t get
char buf[256]
int i
int j
//同样的先去获取CPU的个数
int num = sysconf(_SC_NPROCESSORS_CONF)
printf("system has %d processor(s)\n", num)
for (i = 0i <numi++) {
CPU_ZERO(&mask)
CPU_SET(i, &mask)
//这个其实和设置进程的亲和力基本是一样的
if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) <0) {
fprintf(stderr, "set thread affinity failed\n")
}
CPU_ZERO(&get)
if (pthread_getaffinity_np(pthread_self(), sizeof(get), &get) <0) {
fprintf(stderr, "get thread affinity failed\n")
}
for (j = 0j <numj++)
{
if (CPU_ISSET(j, &get))
{
printf("thread %d is running in processor %d\n", (int)pthread_self(), j)
}
}
j = 0
while (j++ <100000000) {
memset(buf, 0, sizeof(buf))
}
}
pthread_exit(NULL)
}
int main(int argc, char *argv[])
{
pthread_t tid
if (pthread_create(&tid, NULL, (void *)myfun, NULL) != 0)
{
fprintf(stderr, "thread create failed\n")
return -1
}
pthread_join(tid, NULL)
return 0
}
第一种:linux的shell命令行方式,命令名字为taskset。第二种就是代码实现级别的了,pthread_setaffinity_np和sched_setaffinity函数接口。第一种方式我已经验证过了,确实可行。同时验证了我心中的疑问:如果将某个线程绑定到某个物理核上之后,在此线程运行结束前,会不会有别的线程被调度到此物理核上执行? 写了一个死循环验证了下,发现绑定之后是不会调度别的线程在此核上运行的!(肉眼观察的,时不时观察下,没发现别的线程在此核上执行;对比了下没有绑定的情况,会发现过段时间此线程就会被调度到别的核心上执行)
此种方式有个问题,就是只有线程运行起来后才会被绑定到某个核上,不够及时。
具体的方式为:
1.首先根据系统的差别运行如下安装命令:
sudo apt-get install util-linux(Debian,Ubuntu or Linux Mint)
sudo yum install util-linux (Fedora,CentOS or RHEL)
2.相关命令的使用:
2.1 使用命令 taskset -p <PID>来获得此Process的 CPU affinity。
eg: taskset -p 2915 ------>pid 2915's current affinity mask:ff; ff=="1111 1111",没一个1代表一个核,共8个核,能用的核数也为8个核。
2.2 使用命令 taskset -cp <PID>可获得数字形式的CPU affinity。
eg: taskset -cp 2915 ------>pid 2915's current affinity list: 0--7。
接下来为将进程pin到某个核上的命令;
2.3 taskset -p <COREMASK> <PID>
eg:taskset -p 0x11 9030 ------>pid 9030's current affinity mask: ff , pid 9030's new affinity mask: 11 。意思就是将此进程绑定到了CPU core 0 and 4。
2.4 taskset -cp <CORE-LIST> <PID>
eg:taskset -cp 0,4 9030 ------>the same as below.
With "-c" option, you can specify a list of numeric CPU core IDs separated by commas, or even include ranges (e.g., 0,2,5,6-10).
2.5 taskset <COREMASK> <EXECUTABLE>
eg: taskset 0x1 xxxx ----->"xxxx" represented the name of one program.
另外:参考文章最后的位置说到,绑定到此物理核之后,别的进程(线程)还可以调度到此核上执行,但是没说绑定的这个线程没执行完之前是否会被别的线程挤掉。根据我的观察是不会被挤掉,这我在文章的开头也有提到。
1、物理CPU数:机器主板上实际插入的cpu数量,比如说你的主板上安装了一块8核CPU,那么物理CPU个数就是1个,所以物理CPU个数就是主板上安装的CPU个数。
2、物理CPU核数:单个物理CPU上面有多个核,物理CPU核数=物理CPU数✖️单个物理CPU的核
3、逻辑CPU核数:一般情况,我们认为一颗CPU可以有多个核,加上intel的超线程技术(HT), 可以在逻辑上再分一倍数量的CPU core出来。逻辑CPU核数=物理CPU数✖️单个物理CPU的核*2
4、超线程技术(Hyper-Threading):就是利用特殊的硬件指令,把两个逻辑CPU模拟成两个物理CPU,实现多核多线程。我们常听到的双核四线程/四核八线程指的就是支持超线程技术的CPU。
1、并行:两件(多件)事情在同一时刻一起发生。
2、并发:两件(多件)事情在同一时刻只能有一个发生,由于CPU快速切换,从而给人的感觉是同时进行。
3、进程和线程
进程是资源分配的最小单位,一个程序有至少一个进程。线程是程序执行的最小单位。一个进程有至少一个线程。
线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
4、单核多线程:单核CPU上运行多线程, 同一时刻只有一个线程在跑,系统进行线程切换,系统给每个线程分配时间片来执行,看起来就像是同时在跑, 但实际上是每个线程跑一点点就换到其它线程继续跑。
5、多核多线程:每个核上各自运行线程,同一时刻可以有多个线程同时在跑。
1、对于单核:多线程和多进程的多任务是在单cpu交替执行(时间片轮转调度,优先级调度等),属于并发
2、对于多核:同一个时间多个进程运行在不同的CPU核上,或者是同一个时间多个线程能分布在不同的CPU核上(线程数小于内核数),属于并行。
3、上下文切换:上下文切换指的是内核( *** 作系统的核心)在CPU上对进程或者线程进行切换。上下文切换过程中的信息被保存在进程控制块(PCB-Process Control Block)中。PCB又被称作切换帧(SwitchFrame)。上下文切换的信息会一直被保存在CPU的内存中,直到被再次使用。
CPU 亲和性(affinity)就是进程要在某个给定的 CPU 上尽量长时间地运行而不被迁移到其他处理器的倾向性。这样可以减少上下文切换的次数,提高程序运行性能。可分为:自然亲和性和硬亲和性
1、自然亲和性:就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器,Linux 内核进程调度器天生就具有被称为 软 CPU 亲和性(affinity) 的特性,这意味着进程通常不会在处理器之间频繁迁移。这种状态正是我们希望的,因为进程迁移的频率小就意味着产生的负载小。Linux调度器缺省就支持自然CPU亲和性(natural CPU affinity): 调度器会试图保持进程在相同的CPU上运行。
2、硬亲和性:简单来说就是利用linux内核提供给用户的API,强行将进程或者线程绑定到某一个指定的cpu核运行。Linux硬亲和性指定API:taskset .
taskset [options] mask command [arg]...
taskset [options] -p [mask] pid
taskset 命令用于设置或者获取一直指定的 PID 对于 CPU 核的运行依赖关系。也可以用 taskset 启动一个命令,直接设置它的 CPU 核的运行依赖关系。
CPU 核依赖关系是指,命令会被在指定的 CPU 核中运行,而不会再其他 CPU 核中运行的一种调度关系。需要说明的是,在正常情况下,为了系统性能的原因,调度器会尽可能的在一个 CPU 核中维持一个进程的执行。强制指定特殊的 CPU 核依赖关系对于特殊的应用是有意义的
CPU 核的定义采用位定义的方式进行,最低位代表 CPU0,然后依次排序。这种位定义可以超过系统实际的 CPU 总数,并不会存在问题。通过命令获得的这种 CPU 位标记,只会包含系统实际 CPU 的数目。如果设定的位标记少于系统 CPU 的实际数目,那么命令会产生一个错误。当然这种给定的和获取的位标记采用 16 进制标识。
0x00000001
代表 #0 CPU
0x00000003
代表 #0 和 #1 CPU
0xFFFFFFFF
代表 #0 到 #31 CPU
-p, --pid
对一个现有的进程进行 *** 作,而不是启动一个新的进程
-c, --cpu-list
使用 CPU 编号替代位标记,这可以是一个列表,列表中可以使用逗号分隔,或者使用 "-" 进行范围标记,例如:0,5,7,9
-h, --help
打印帮助信息
-V, --version
打印版本信息
如果需要设定,那么需要拥有 CAP_SYS_NICE 的权限;如果要获取设定信息,没有任何权限要求。
taskset 命令属于 util-linux-ng 包,可以使用 yum 直接安装。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)