18---进程管理


说明:进程组,会话等会写在 C系统编程 系列博文中,Linux 运维系列的博文中不涉及这些内容
=========
进程状态
D 不可终端的睡眠
S 可中断的睡眠
R 运行或就绪
T 停止
Z 僵尸
PID 为 0 的进程通常是调度进程,被称为交换进程(swapper)
PID 为 1 的进程即 init,在 CentOS 7 上改为 systemd 早期的 init 会读取初始化文件,比如/etc/inittab,/etc/init.d 中的文件等。
=========================
进程信息查看( 瞬态 & 动态)
---------瞬态---------
pstree  
-p    显示PID
-u    显示进程的 euid     <----普通用户执行 passwd ,然后在另一终端 pstree -u 可得之
---------
ps   <---  默认显示与当前会话 shell 相关的进程; UNIX 风格
-l    长格式,增加显示部分字段,如 F(Flag:1-->fork 但未exec 4-->root权限)
F S   UID    PID   PPID  C PRI  NI  ADDR SZ       WCHAN  TTY     TIME        CMD
4 S     0   2629   2624  0  80   0   -        27121  wait        pts/0   00:00:00  bash
4 R     0   2651   2629  8  80   0   -        27036   -            pts/0   00:00:00  ps
-e    所有进程
-f     CMD 以全路径显示
-F    更全信息,增加 RSS(Resident Set Size),PSR(Processor) 等字段
-H   hierarchy,层级显示
-eo pid,tid,class,rtprio,ni,pri,psr, pcpu,stat,comm  <--- o 选项后给出要显示的 column
---------
ps    <--- BSD 风格,我喜欢
a    所有与终端相关的进程     
x    显示与终端无关的进程(掺杂着部分与终端相关的进程,不纯啊)
u    显示进程所有者(即进程的 euid)及其他信息,如 CPU 利用率
f     显示父子关系
axo user,comm(cmd), stat,euid,ruid,tty,tpgid,sess,pgrp,ppid, pid,pcpu,ni,pri,rtprio,psr,%cpu,%mem   <--- o 选项后给出要显示的 column
例子:ps o pid,cmd,stat -p 3808  // 搭配 -p 查询指定 pid (可用 pidof COMMND 获得某程序 PID)
问题:因为是取的瞬态值,所以 %CPU 的值加起来可能会超过 100%,而 top 命令中的 %CPU 则不会出现此情况。 <--- 这样理解对吗?
USER        PID %CPU %MEM   VSZ       RSS     TTY    STAT  START   TIME  COMMAND
root          1     0.0      0.0        19364   1620   ?        Ss      16:19    0:01   /sbin/init
root          2     0.0      0.0        0           0         ?        S       16:19    0:00   [kthreadd]
root          3     0.0      0.0        0           0         ?        S       16:19    0:00   [migration/0]
root          4     0.0      0.0        0           0         ?        S       16:19    0:00   [ksoftirqd/0]
VSZ:Virtual memory size of the process in KiB (1024-byte units). Device mappings are currently excluded; this is subject to change.
RSS:Resident Set Size, the non-swapped physical memory that a task has used (in kiloBytes).
---------动态---------
top
-d #    刷新时长为 # 秒,缺省为5秒
-p #    指定查看PID为 # 的进程
-b      不是持续刷屏,而是现实几个batch后就退出
-n #   和-b一起用,即批模式下,共显示多少批
top -d 1 -b -n 2
M   按mem排序
P    按CPU使用排序
T    按累计时间排序
N   以PID来排序
r     renice,修改指定进程的nice值
k    杀死指定进程
q    退出
s    修改刷新时间间隔
补充:top的默认第一行可以通过 uptime 得到,其实 w 的默认第一行显示也是这些信息
System load averages is the average number of processes that are either in a runnable or uninterruptable state.  A process in a runnable state  is  either using  the CPU or waiting to use the CPU.  A process in uninterruptable state is waiting for some I/O access, eg waiting for disk.  The averages are taken over the three time intervals.  Load averages are not normalized for the number of CPUs in a system, so a load average of 1 means a single CPU system is loaded all the time while on a 4 CPU system it means it was idle 75% of the time.
pidof
pidof  COMMAND    查看指定 COMMAND 的 PID
=========
内存映像
pmap(Report memory map of a process)
-d    show the device format
-x    show the extended format
=========================
vm 及 I/O 信息查看( 瞬态 )
vmstat
Report virtual memory statistics
vmstat #    每隔#s刷新一次
vmstat #1 #2    每隔#1秒执行一次,但只取#2个结果
free
查看内存使用情况
free { -b | -k | -m | -h }
-t     total,多出一行total(mem+swap)
iostat 
Report Central Processing Unit (CPU) statistics and input/output statistics for devices and partitions.
dstat 
一款可以统计 N 多数据的工具,需要自己手动安装
===============================
操作进程优先级 & 给进程发信号
nice值
top中,PR 与 NI 总是差一个固定的值,如果 NI 减小,PR亦减小,调整 nice 值以达到调整 PR 的目的
nice 值对 root 来讲可调整的范围为-20~19,对普通该用户其范围为0~19
设定nice值得方法:
1.  nice -n # COMMAND    即执行时就设定
2.  renice nice_Value PID
kill
kill -s signal PID,或直接 kill -signal PID   常见的 signal 有如下几个(不区分大小写,如写成 sighup 也可以,甚至 hup 也可以,1 也可以)
1 -->  SIGHUP    重读配置文件
2 -->  SIGINT     ctrl+c
3 -->  SIGQUIT   ctrl+\
9 -->  SIGKILL    猝死
15 -->  SIGTERM    按手续终结生命,有托孤之用(不指明信号,默认发的就是 SIGTERM)
18 -->  SIGCONT   继续运行
19 -->  SIGSTOP    后台休眠    // 和下面要讲的前后台任务相关
kill 和 term 对杀掉的子进程都进入僵尸态,效果看上去一样。但是对父进程不一样,kill 父进程,子进程也被 kill 掉。但是如果 terminate 一个父进程,子进程会被托付给 init/systemd 进程,比较人道。
//zom.c
#include<stdio.h>
#include<stdlib.h>

int main()
{
    pid_t   pid;

    pid=fork();
    switch(pid)
    {
        case -1:
            printf("something wrong.\n");
            exit(-1);
        case 0:
            printf("this is child.\n");
            sleep(100);
            exit(0);
        default:
            sleep(150);
            printf("this is parent.\n");
            exit(0);
    }
}
gcc -o zom zom.c,并运行之
先 pidof zom, 然后试着给父进程和子进程发 SIGKILL 和 SIGTERM
killall
killall COMMAND
pkill  <--- 按模式杀,大规模地杀
-signal # 或 -#
-u    指定 euid
-U   指定 uid
-t    指定终端(若发信号15,只能杀死 shell 子进程,不能杀死 shell,杀 shell 必须用 9, WHY),如 pkill -9 -t pts/0 ,使用时终端名需去掉 /dev/ 前缀
pgrep  <--- 查找符合条件的 pid
-u    指定 euid
-U   指定 uid
-t    指定终端

========================================
前后台作业  进程的前后台是针对终端 或 shell 进程来讲的
命令在前台霸占终端,执行时可用 & 将命令从前台丢到后台“执行”----->  COMMAND &    
注意:如果命令有大量的到 STDOUT 输出,会把命令提示符冲掉,造成任务没有被丢到后台的假象,针对这种情况使用重定向,把输出到STDOUT的数据流写到某个文件中就ok了。
将命令从前台丢到后台“stop”----->  命令执行后,ctrl+z
总结:
对于CentOS7,后台作业是与终端挂钩的。终端挂了,就都挂了。但 bash 脚本是个例外,若 bash脚本 作业状态为 running,则终端挂了会被托管,若 bash脚本 作业状态为 stopped,则终端挂了,脚本也挂了。
对于CentOS6,二进制程序 作业状态为 running,则终端挂了会被托管,若作业状态为 stopped,则终端挂了,二进制程序也挂了。若 bash脚本 作业状态为 running,则终端挂了会被托管,若 bash脚本 作业状态为 stopped,则终端挂了,脚本也挂了。

系统
ELF 且 running
ELF 且 stopped
.sh 且 running
.sh 且 stopped
CentOS 7
被杀死
被杀死
被托管
被杀死
CentOS 6
被托管
被杀死
被托管
被杀死
例外:若执行(COMMAND &),即 command & 被小括号括起来,则直接被 init/systemd 托管,而与终端脱钩,与下面要讲的 nohup 类似。这里说的 command 包括了 ELF 和 shell 脚本。
(ps axo cmd,pid,ppid,tty | grep yourprogram)查看实验用ELF或sh文件的进程信息
nohup (run a command immune to hangups, with output to a non-tty )
nohup COMMAND 后关闭终端, COMMAND 依然运行,只不过 tty 显示为问号 一般 nohup 的 COMMAND 后加上 & 以释放前台
-------------------
前后台进程的管理
jobs(查看后台进程队列
-l     long format,  列出 job number 外,同时列出 PID
-r     running,列出后台运行状态的进程
-s    stop,列出后台stop状态的进程
最新加入队列的 job 用 +标注,次新的用 - 号标注,第三名以后的就爱谁谁了。
fg  [ %jobnumber ]
如果不指定 jobnumber,会把最近加入队列的 job(即 + 标注的)调入前台并使之 running
bg  [ %jobnumber ]
如果不指定 jobnumber,会把最近加入队列的 job(即 + 标注的)设置为后台 running
kill -signal %jobnumber
kill 支持的 signal 可通过 kill -l 查询,较重要的 signal 参考上文
注意:kill 要杀后台的 job ,不要忘记 %
对于后台的进程虽然 ctrl+c 不能终结它( ctrl+c 只被设计用来终结前台进程组的,因为前台只有一个进程组,而后台可能有多个,不知道要给哪一个执行 ctrl+c),但是 SIGINT 还是可以终结它的。