为什么要知道某个进程开启了多少线程?
- 好奇,这个很重要
- 性能调优
概念澄清
- 这里所说的线程指的是内核级别的线程,不是用户态线程,所谓用户态线程是指不依赖操作系统而是在用户态下实现的执行流调度。
- 这里的线程个数指的是进程运行时的线程个数,这个数值会随着线程的创建和销毁而动态变化。
- 本文主要关注Linux平台。
背景知识与原理
- /proc/{pid}
/proc/{pid}下记录了每个进程运行时的所有关键信息,那这些信息是谁来生成的呢,答案是Linux内核。
Linux内核在执行你写的程序时,将所有关键信息写到了/proc/{pid}下,因此你可以通过查看这个目录下的信息来或者进程的运行时行为,这对于那些好奇内核是如何运行程序的同学是非常重要的。
你可以把这个目录下的信息理解为Linux内核在执行你写的程序时所打印的Log。通过该Log你就可以知道进程开启了多少线程了。
- 进程号:pid
Linux内核在执行程序时需要为每个进程分配一个id,类似于身份证号的作用,用于识别进程,因此想获取某个进程开启了多少线程首先必须要知道是进程id。
实验开始
- 实验一:最简单的情况
我们来看一下最简单的helloworld程序有多少线程:
#include <iostream>
#include <unistd.h>
int main()
{
std::cout<<"helloworld";
sleep(1000); //保持进程不退出
return 0;
}
接下来编译运行:
$ g++ s.cpp -o helloworld
$ ./helloworld &
[1] 125626
我们可以发现,该helloworld进程的进程号是125626,有了进程号我们就可以查看该进程开启多少线程了。运行如下命令:
$ cat /proc/125626/status | grep Threads
Threads: 1
可以看到,和我们的预期是一样的,该helloworld进程仅有开启了一个线程。
- 实验二:稍复杂的情况
在这个实验中,我们动态创建线程:
#include <pthread.h>
#include <unistd.h>
void* func(void* arg) {
sleep(10000);
}
int main()
{
pthread_t id;
for (int i=0;i<10;i++) {
pthread_create(&id,NULL, func,NULL);
sleep(10);
}
return 0;
}
在这个程序当中,我们动态创建了10个线程,每创建一个线程sleep10秒,每个线程sleep10000秒。编译运行:
$ g++ s.cpp -o helloworld
$ ./helloworld &
[1] 125667
$ cat /proc/125667/status | grep Threads
Threads: 2
$ cat /proc/125667/status | grep Threads
Threads: 2
$ cat /proc/125667/status | grep Threads
Threads: 3
$ cat /proc/125667/status | grep Threads
Threads: 4
$ cat /proc/125667/status | grep Threads
Threads: 5
$ cat /proc/125667/status | grep Threads
Threads: 6
$ cat /proc/125667/status | grep Threads
Threads: 10
可以看到,当用cat查看线程数的时候进程已经创建了两个线程,如果快速查看两次,发现线程数据都是2,但是隔一段时间后(超过10s)会发现线程数为3,到最后线程数为10,符合我们的预期。
结论
通过命令 "cat /proc/{pid}/status | grep Threads" 可以动态查看进行运行时的线程个数。
One more thing...
如果你喜欢该文章,欢迎关注我的微信公共账号,码农的荒岛求生,获取更多计算机内功的知识。
计算机内功决定程序员职业生涯高度
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。