linux 在分析问题时,经常要查看进程的相关信息,但要进一步深入剖析时,就需要查看进程下的各线程的情况。先说下,如何了解一个进程到底开启了多少线程?

一、proc查看

该方法是个人最为推荐,也最喜欢的一种方法。进程文件下,有几种方式可以获取目前进程开启的进程数。

查看status文件:

1# cat /proc/5877/status
2Name:   mysqld
3State:  S (sleeping)
4Tgid:   5877
5Pid:    5877
6PPid:   1
7……………………省略
8Threads:        107
9……………………省略

上面的threads 就是mysqld进程(这里pid是5877)开启的线程数,为107个。

查看sched文件:

1# cat /proc/5877/sched
2mysqld (5877, #threads: 107)
3---------------------------------------------------------
4se.exec_start                      :    3493311530.012024
5se.vruntime                        :      11069857.718492
6se.sum_exec_runtime                :        193606.973849
7se.statistics.wait_start           :             0.000000
8………………省略

第一行就指出了mysqld的pid和总线程数。

查看线程的具体情况:

1# ls /proc/5877/task
212134  17039  22613  22619  22626  22631  22636  22641  22646  22653  22661  22671  22681  22690  22699  22725  22741  29749  5891  5896  5920  9441
312142  17161  22614  22621  22627  22632  22637  22642  22648  22654  22663  22673  22683  22692  22701  22727  22743  30458  5892  5897  5921  9764
412290  17163  22615  22622  22628  22633  22638  22643  22649  22655  22665  22675  22684  22693  22703  22735  22745  5877   5893  5898  5930
512352  17253  22616  22624  22629  22634  22639  22644  22650  22656  22667  22676  22687  22695  22705  22738  22747  5889   5894  5918  644
612874  22612  22617  22625  22630  22635  22640  22645  22652  22658  22669  22679  22689  22697  22723  22740  2708   5890   5895  5919  9318

task下是以线程id 值命名的目录,可以使用ls |wc 统计出的值和上面两种方式查出的结果一样。进入各线程id的目录,可以查看具体线程的资源信息。

注:上面查看文件的方法,主要是对单进程的线程统计。如像统计apache、nginx、zabbix这类程序会同时开启N个进程。如果要统计这类程序的线程数,就是所有进程下的线程数的之和。

二、pstree查看法

该方法也属于相对比较简单的方法,如下:

 1# pstree
 2init─┬─acpid
 3     ├─apache2───15*[apache2]
 4     ├─atd
 5     ├─cf-execd
 6     ├─cf-serverd
 7     ├─cron
 8     ├─dbus-daemon
 9     ├─dhclient3
10     ├─6*[getty]
11     ├─java───13*[{java}]
12     ├─mysqld───106*[{mysqld}]
13     ├─nrpe
14     ├─ntpd
15     ├─rsyslogd───3*[{rsyslogd}]
16     ├─snmpd
17     ├─snmptt───snmptt
18     ├─sshd───sshd───sshd───bash───sudo───su───bash───pstree
19     ├─udevd───2*[udevd]
20     ├─upstart-socket-
21     ├─upstart-udev-br
22     ├─vsftpd
23     ├─whoopsie───{whoopsie}
24     ├─zabbix_agentd───4*[zabbix_agentd]
25     └─zabbix_server─┬─105*[zabbix_server]
26                     └─zabbix_server───sh───fping

如上面,apache共有16个线程(15+1),mysqld有107个线程(106+1)。如果想查看某个进程的详细线程情况,可以使用pstree -p 的方法:

1# pstree -p  5877
2mysqld(5877)─┬─{mysqld}(5889)
3             ├─{mysqld}(5890)
4             ├─{mysqld}(5891)
5             ├─{mysqld}(5892)
6             ├─{mysqld}(5893)
7              ……………………省略
8# pstree -p 5877 |wc -l
9106

三、ps命令查看法

ps命令中与线程相关的参数比较多,具体可以使用man ps|grep threads 查看

  • H Show threads as if they were processes.
  • -L Show threads, possibly with LWP and NLWP columns.
  • m Show threads after processes.
  • -m Show threads after processes.
  • -T Show threads, possibly with SPID column.

这里主要以-L参数为例:

 1#  ps -eLf | grep mysql
 2mysql     5877     1  5877  0  107 Jun13 ?        00:03:13 /usr/sbin/mysqld
 3mysql     5877     1  5889  0  107 Jun13 ?        00:00:00 /usr/sbin/mysqld
 4mysql     5877     1  5890  0  107 Jun13 ?        00:00:39 /usr/sbin/mysqld
 5mysql     5877     1  5891  0  107 Jun13 ?        00:01:07 /usr/sbin/mysqld
 6mysql     5877     1  5892  0  107 Jun13 ?        00:01:24 /usr/sbin/mysqld
 7mysql     5877     1  5893  0  107 Jun13 ?        00:01:24 /usr/sbin/mysqld
 8mysql     5877     1  5894  0  107 Jun13 ?        00:01:22 /usr/sbin/mysqld
 9mysql     5877     1  5895  0  107 Jun13 ?        00:21:38 /usr/sbin/mysqld
10………………省略

-L参数显示进程,并尽量显示其LWP(线程ID)和NLWP(线程的个数)。上面命令查询结果的第二列为PID,第三列为PPID,第四列为LWP,第六列为NLWP。

ps 属于linux下相对比较全能且强大的命令,其还可以查看具体某个线程运行在哪个CPU上,如下:

 1# ps -eo ruser,pid,ppid,lwp,psr,args -L | grep mysql
 2mysql     5877     1  5877   0 /usr/sbin/mysqld
 3mysql     5877     1  5889   1 /usr/sbin/mysqld
 4mysql     5877     1  5890   1 /usr/sbin/mysqld
 5mysql     5877     1  5891   0 /usr/sbin/mysqld
 6mysql     5877     1  5892   0 /usr/sbin/mysqld
 7mysql     5877     1  5893   0 /usr/sbin/mysqld
 8mysql     5877     1  5894   0 /usr/sbin/mysqld
 9mysql     5877     1  5895   2 /usr/sbin/mysqld
10mysql     5877     1  5896   3 /usr/sbin/mysqld
11mysql     5877     1  5897   0 /usr/sbin/mysqld
12mysql     5877     1  5898   3 /usr/sbin/mysqld

其中,每一列依次为:用户ID,进程ID,父进程ID,线程ID,运行该线程的CPU的序号,命令行参数(包括命令本身)。

四、top命令查看

同样top也属于全能型命令(也是相对的),在top命令后,按H键;或者top -H 可以显示各个线程的情况。在top中也可以查看进程(或线程)在哪个CPU上执行的,执行top后,按f,按j(选中* J: P = Last used cpu (SMP)),然后按空格或回车退出设置,在top的显示中会多出P这一列是最近一次运行该线程(或进程)的CPU。

五、pstack查看

pstack命令一般情况下用不到,其是一个栈跟踪的命令 。一般和 core dump和程序分析相关,也可以获取线程的详细信息。如:

 1# pstack 2178
 2Thread 4 (Thread 0xb7fd7b90 (LWP 2179)):
 3#0  0x00110402 in __kernel_vsyscall ()
 4#1  0x009418d5 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/i686/nosegneg/libpthread.so.0
 5#2  0x00163f4f in ?? () from /usr/lib/libisc.so.15
 6#3  0x0093d5e2 in start_thread () from /lib/i686/nosegneg/libpthread.so.0
 7#4  0x005d4d7e in clone () from /lib/i686/nosegneg/libc.so.6
 8Thread 3 (Thread 0xb75d6b90 (LWP 2180)):
 9#0  0x00110402 in __kernel_vsyscall ()
10#1  0x00941c02 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib/i686/nosegneg/libpthread.so.0
11#2  0x0017a4d2 in isc_condition_waituntil () from /usr/lib/libisc.so.15
12#3  0x00166890 in ?? () from /usr/lib/libisc.so.15
13#4  0x0093d5e2 in start_thread () from /lib/i686/nosegneg/libpthread.so.0
14#5  0x005d4d7e in clone () from /lib/i686/nosegneg/libc.so.6
15Thread 2 (Thread 0xb6bd5b90 (LWP 2181)):
16#0  0x00110402 in __kernel_vsyscall ()
17#1  0x005d5496 in epoll_wait () from /lib/i686/nosegneg/libc.so.6
18#2  0x001759c1 in ?? () from /usr/lib/libisc.so.15
19#3  0x0093d5e2 in start_thread () from /lib/i686/nosegneg/libpthread.so.0
20#4  0x005d4d7e in clone () from /lib/i686/nosegneg/libc.so.6
21Thread 1 (Thread 0xb7fd86d0 (LWP 2178)):
22#0  0x00110402 in __kernel_vsyscall ()
23#1  0x0052a5c7 in sigsuspend () from /lib/i686/nosegneg/libc.so.6
24#2  0x00168262 in isc_app_run () from /usr/lib/libisc.so.15
25#3  0x002e9623 in main ()

以上是对named进程进行的一个分析。可以看出一分有四个线程,对每个线程的程序调用程序print 出来了。