发布: 2010-4-02 14:11 | 作者: 选择多灵活多 | 查看: 9次
1)进程的状态的概述:
1.1)Running(R),运行或将要运行
1.2)Interruptible(S),被阻断而等待一个事件,可能会被一个信号激活
1.3)Uninterruptible(D),被阻断而等待一个事件,不会被信号激活
1.4)Stopped(T),由于任务的控制或者外部的追踪而被终止,比如:strace
1.5)Zombie(Z),僵死,但是它的父进程尚未调用wait函数.
1.6)Deal(X),这个永远看不见
在内核源代码中的定义如下:
=====================================================
/usr/src/linux/fs/proc/array.c
static const char *task_state_array[] = {
};
=====================================================
在ps命令的帮助中定义如下:
PROCESS STATE CODES
======================================================
2)分析不可被中断的睡眠进程:
2.1)重现:
终端1)
strace -o/tmp/dd.log dd if=/dev/zero f=/share/test count=65535 bs=65535
终端2)
more /tmp/dd.log
出现大量的write和read函数调用,即调用65535次,每次读写65535个字节
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 65535) = 65535
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 65535) = 65535
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 65535) = 65535
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 65535) = 65535
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 65535) = 65535
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 65535) = 65535
终端3)
ps aux|grep dd
root
2.2)分析:
系统进入这种不可中断是很少发生的,即使发生也是一个短暂的状态,引起这种状态的发生一般是驱动程序.
例如:驱动程序可能正在特殊的设备上等待通过检测的响应,但又要保证自己不在可中断睡眠状态(S)被中断.所以驱动程序会把进程切换到不可中断的睡眠状态,直到硬件已返回到已知状态.
可以通过访问一个慢设备来观察不可中断的睡眠状态,比如CDROM这样的设备
例如:
dd if=/dev/cdrom f=/dev/null &
进程在一个不可中断的状态是十分危险的,你不能用kill -9杀掉它
例如:
一个有问题的驱动程序访问一个有问题的设备,设备不给驱动程序响应,驱动程序永远得不到响应,而又永远等待响应.
3)分析被跟踪或被停止的进程状态(T)
3.1)重现被跟踪时的状态:
终端1)
strace top
终端2)
ps auxf|grep top
root
root
在用strace跟踪top执行的时候,top进程为T的状态
3.2)重现被停止的进程状态:
停止进程有三种手段:
3.2.1)发送SIGTSTP信停止进程.
-SIGTSTP的信号相当于CTRL+Z的组合键来终止正在前台运行的进程.
终端1)
vi /etc/passwd
终端2)
kill -SIGTSTP 12029
查看进程状态:
ps auxf
root
root
终端1)
查看放到后台的作业
jobs
[1]+
用fg将作业切换到前台
fg
3.2.2)进程自已终止自己,标准输入引起进程停止
一个终端利用常规的后台和前台进程管理进程,一个终端有且只有一个前台进程,只有这个进程可以接受键盘的输入,其它任何开始于终端的进程都被认为是后台进程,但是当后台进程试图从标准办入读取数据时,终端将发送一个SIGTTIN终端它,因为这里只有一个输入设备键盘,只能用于前台进程.
这里的前后台进程概念仅限于终端的范围.
SIGTTIN 当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN 信号. 缺省时这些进程会停止执行.
终端1)
尝试在后台运行read命令,因为后台进程不能从终端获取标准输入,所以进程将会收到信号SIGTTIN,使进程进入停止状态.
read x &
[1] 12057
[1]+
终端2)
jobs
[1]+
查看进程,12057这个PID就是read x&,现在看到是-bash,它的状态已经是T了
ps aux
root
用SIGCONT来唤醒
kill -SIGCONT 12057
终端1)
输入回车后,12057的进程依然会进入停止状态,也就是阻塞,只有会放到前台后,它才能完成输入.
fg
read x
hello
3.2.3)进程自已终止自己,标准输出引起进程停止
终端有一个tostop(终端输出终止)设置,在大多数系统里默认是关闭.
当是关闭的状态时,后台进程可以随时在终端写内容,如果是开启状态时,后台进程向标准输出写数据时就会被终止.
开启tostop
stty tostop
向标准输出写数据,被停止了
echo hello world &
[1] 12125
[1]+
jobs
[1]+
关闭tostop
stty -tostop
jobs
[1]+
向标准输出写数据恢复正常了
fg
echo hello world
hello world
4)分析进程的可中断睡眠态与运行态
编写一个小程序测试睡眠态与运行态之后的转换 :
=====================================================
#include <stdio.h>
#include <math.h>
#include <unistd.h>
#include <stdlib.h>
void
run_status(void)
{
}
int
main (void)
{
}
======================================================
编译链接后:
gcc -Wall -o pisqrt a.c -lm
终端1)
监控pisqrt进程
watch -n 1 "ps aux|grep pisqrt|grep -v ps|awk '{print $2}'|sort -k 8"
终端2)
strace ./pisqrt
显示如下:
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\200X\1"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1572440, ...}) = 0
old_mmap(NULL, 1279916, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x49e000
old_mmap(0x5d1000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x132000) = 0x5d1000
old_mmap(0x5d4000, 10156, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x5d4000
close(3)
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75e3a60, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
munmap(0xb75e4000, 75579)
此时切换到终端1看pisqrt进程状态,此时为R状态:
root
root
root
之后pisqrt进程进入S状态,因为执行了sleep(10)函数,10秒之后pisqrt再次进入R状态.最终退出.
分析:
pisqrt占用CPU时间片时状态为R,而在调用sleep函数后为S,系统大多数进程状态都为S,比如APACHE和ORACLE,
而处于S状态不一定是调用了sleep函数,因为IO也会让进程处于睡眠态.
而我们可以启动多个pisqrt程序,这时在系统中会有多个R状态的进程.也就是说CPU个各数与R进程是没有直接关联的.
5)分析进程的僵死态(Z)
当一个进程退出时,它并不是完全消失,而是等到它的父进程发出wait系统调用才会完全消失,除非父进程发出wait系统调用终止进程,
否则该进程将一直处于所谓的僵死状态,等待它的父进程终止它.如果父进程终止了运行而没有撤销子进程,那么这些进程将被进程init收养.
init进程定期调用wait来收养这些未被撤消的进程.
先制造一段僵尸程序,如下:
=============================
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int
main (){
}
}
===========================================
编译
gcc -Wall defunct.c -o defunct
终端1:
watch -n 1 "ps auxf|grep defunct|grep -v ps|grep -v grep|awk '{print $2}'|sort -k 8"
终端2:
执行./defunct
查看终端1:
root
root
20秒后查看终端2:
child pid=7281
parent pid=7280
关于信号集的描述:/usr/include/bits/signum.h
#define SIGCLD
#define SIGCHLD
在上面程序的基础上加入wait函数即可将SIGCHLD信号回收
修改后的程序如下:
=================================
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int
main (){
}
}
==========================================
6)最后的进程X (dead)
指死掉的进程
最后4种附加的状态....
W状态:不驻留内存
<状态:nice小于0
N状态:nice大于0
L状态:有锁住的页面
这部分在ps的源代码(output.c)有描述:
===================================
static int
pr_stat(void)
{
}
联系客服