一步步理解Linux进程(1)--进程基础知识

0. 说明

作者:Gao Peng<gaopenghigh@gmail.com>
本文章由Gao Peng编写,转载请注明出处。

1. 基本概念

进程
进程是处于执行期的程序以及相关资源的总称,注意包含了两个方面:
  • 程序代码。
  • 资源。比如说打开的文件,挂起的信号,内核内部数据,处理器状态,一个或多个具有内存映射的内存地址空间,一个或多个执行线程,存放全局变量的数据段等。
PID
任意一个进程通过PID作为标识,PID一般是一个正整数。

线程
对于Linux,内核并没有线程这个概念。Linux把所有的线程都当做进程来实现,线程仅仅被视为一个与其他进程共享某些资源的进程。

进程的状态
进程可以有5种状态:
  • TASK_RUNNING(运行) -- 进程正在执行,或者在运行队列中等待执行。这是进程在用户空间中唯一可能的状态。
  • TASK_INTERRUPTIBLE(可中断) -- 进程正在睡眠(阻塞),等待某些条件的达成。一个硬件中断的产生、释放进程正在等待的系统资源、传递一个信号等都可以作为条件唤醒进程。
  • TASK_UNINTERRUPTIBLE(不可中断) -- 与可中断状态类似,除了就算是收到信号也不会被唤醒或准备投入运行,对信号不做响应。这个状态通常在进程必须在等待时不受干扰或等待事件很快就会发生时出现。例如,当进程打开一个设备文件,相应的设备驱动程序需要探测某个硬件设备,此时进程就会处于这个状态,确保在探测完成前,设备驱动程序不会被中断。
  • __TASK_TRACED -- 被其它进程跟踪的进程,比如ptrace对程序进行跟踪。
  • __TASK_STOPPED -- 进程停止执行。通常这种状态发生在接收到SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU等信号的时候。此外,在调试期间接收到任何信号,都会使进程进入这种状态。


2.ps的使用

ps的参数
Linux中查看进程的最重要的命令是ps,学会ps的使用,就了解了进程的大部分内容。具体的参数都在man手册,常用的参数是:

a 显示所有进程(包括其它用户的进程)
-e 列出所有进程
x 显示无控制终端的进程
u 输出用户名
e 列出程序时,显示每个程序所使用的环境变量
f 显示树状图
-L 显示线程
-o 按照自定义的格式输出信息
-ww 在终端下不截断命令

命令ps aux的输出的各列如下:

$ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

需要解释的是:
VSZ 表示如果一个程序完全驻留在内存的话需要占用多少内存空间;
RSS 指明了当前实际占用了多少内存;
STAT 显示了进程当前的状态:

ps输出的进程状态
进程的状态和其表示符号如下:

D uninterruptible sleep (usually IO)
R running or runnable (on run queue)
S interruptible sleep (waiting for an event to complete)
T stopped, either by a job control signal or because it is being traced
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z defunct ("zombie") process, terminated but not reaped by its parent

For BSD formats and when the stat keyword is used, additional characters may be displayed:

< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
+ is in the foreground process group


3. 进程关系

进程的创建
Linux非常依赖进程创建来满足用户的需求,比如在shell中输入一条命令,shell进程就生成一个新进程,新进程执行shell的另一个拷贝,这个拷贝的过程由fork()函数完成。示例如下:
示例1:
$  ps -u jh -eo user,pid,ppid,stat,cmd
jh       18586  2840 Ss   /bin/bash
jh       19110 18586 R+   ps -u jh -eo user,pid,ppid,stat,cmd


可以看到用户的终端shell的pid是18586,执行ps程序时,进程18586生产了新的子进程19110来运行ps。

示例2:
$ ps -u jh -eo user,pid,ppid,stat,cmd | cat
USER       PID  PPID STAT CMD
jh       18586  2840 Ss   /bin/bash
jh       19130 18586 R+   ps -u jh -eo user,pid,ppid,stat,cmd
jh       19131 18586 S+   cat
示例中ps的输出通过管道传送给cat,可以看到,运行ps的进程(19130)和运行cat的进程(19131)都是bash进程(18586)的子进程。

由此可见,出了初始的内核进程,所有进程都由其父进程fork()产生。
如果一个进程的父进程终止而自己继续运行,则这种进程叫做孤儿进程(orphan process),内核会把init进程(即PID为1)的进程安排为孤儿进程的父进程。

作业
顾名思义,作业就是完成某个任务的进程的集合。作业可以在前台或者后台运行。比如

示例1:
$ cat main.c
在前台启动了一个作业,这个作业只包含了一个进程,即cat。

示例2:
$ ps aux | grep -v root | cat
在前台启动了一个作业,这个作业包含了三个进程,即ps, grep和cat

示例3:
$ps aux | grep -v root | cat&
则是在后台启动了一个包含3个进程的作业

进程组
每个进程除了有一个唯一的PID外,还属于一个进程组。
进程组是一个或多个进程的集合。通常,他们与统一作业相关联,可以接受来自同一终端的各种信号。
每个进程组由一个进程组ID(PGID)标识。当一个进程的PID等于其所在进程组的PGID时,我们称这个进程是该进程组的组长。
$ ps -u jh -eo user,pid,ppid,pgid,stat,cmd | cat | cat
USER       PID  PPID  PGID STAT CMD
jh       18586  2840 18586 Ss   /bin/bash
jh       19299 18586 19299 R+   ps -u jh -eo user,pid,ppid,pgid,stat,cmd
jh       19300 18586 19299 S+   cat
jh       19301 18586 19299 S+   cat
可以看到,19299, 19300, 19301三个进程具有同样的PGID(19299),说明它们属于同一进程组,组长进程为19299.

会话(session)
会话是一个或多个进程组的集合。
同样,会话由会话ID(SID)标识。如果一个进程的PID等于其所在会话的SID,我们称这个进程是该会话的会话首进程。
$ ps aux | less &
[1] 19322
$ ps -u jh -eo user,pid,ppid,pgid,sid,stat,cmd | cat | cat
USER       PID  PPID  PGID   SID STAT CMD
jh       18586  2840 18586 18586 Ss   /bin/bash
jh       19321 18586 19321 18586 T    ps aux
jh       19322 18586 19321 18586 T    less
jh       19323 18586 19323 18586 R+   ps -u jh -eo user,pid,ppid,pgid,sid,stat,cmd
jh       19324 18586 19323 18586 S+   cat
jh       19325 18586 19323 18586 S+   cat
可以看到,上面两条命令执行下来,产生了两个进程组(PGID分别为19321和19323),它们都属于同一个会话(18586)。事实上,由当前控制终端产生的所有进程组都会属于同一个会话。

一个会话中的几个进程组可以被分成一个前台进程组(foreground process group)和一个或多个后台进程组(background process group)。拥有控制终端的进程所在的进程组就是前台进程组,在终端中键入中断键(Control + C),就会把中断信号发给前台进程组中的所有进程。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值