Linux下进程状态
- 进程状态
- fork
- 孤儿进程
- Z(ZOMBIE)僵尸进程
- 危害
- 处理
进程状态
查看进程状态的命令:
ps aux
ps axj 命令
- R(running):可执行状态
并不一定正在占有CPU,它表明进程要么是正在运行,要么是在运行队列里。实际上分为running和ready两种状态。
- S(task_interruptible):可中断的睡眠状态
处于这个状态的进程因为等待某事件的发生,比如soket连接、信号量而被挂起。
- D(task_uninterruptible):不可中断的睡眠状态
进程处于睡眠状态,但是此刻进程是不可中断的。指的并不是CPU不响应外部硬件的中断,而是不响应异步信号。
而TASK_UNINTERRUPTIBLE状态存在的意义就在于,内核的某些处理流程是不能被打断的。如果响应异步信号,程序的执行流程中就会被插入一段用于处理异步信号的流程(这个插入的流程可能只存在于内核态,也可能延伸到用户态),于是原有的流程就被中断了。
- T(task_stopped or task_traced):暂停状态或跟踪状态
向进程发送一个SIGSTOP信号,它就会因响应该信号而进入TASK_STOPPED状态(除非该进程本身处于TASK_UNINTERRUPTIBLE状态而不响应信号)。(SIGSTOP与SIGKILL信号一样,是非常强制的。不允许用户进程通过signal系列的系统调用重新设置对应的信号处理函数。)
向进程发送一个SIGCONT信号,可以让其从TASK_STOPPED状态恢复到TASK_RUNNING状态。
- X(task_dead - exit_dead):退出状态,进程即将被销毁
这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
- Z(task_dead - exit_zombie):退出状态,进程成为僵尸状态。
进程在退出的过程中,处于TASK_DEAD状态。
在这个退出过程中,进程占有的所有资源将被回收,除了task_struct结构(以及少数资源)以外。于是进程就只剩下task_struct这么个空壳,故称为僵尸。
fork
一个进程可以通过调用fork函数来创建一个新的进程,即子进程。
进程参数:
返回值的区别:
- 子进程返回值0。因为子进程的父进程是可以唯一确定的,通过getpid方法可以获取到父进程id。
- 父进程返回的是新创建的子进程的ID,因为父进程可以创建多个子进程,没有函数可以获取该线程的所有子线程的所有id。
孤儿进程
孤儿进程就是父进程先于子进程退出。
[root@iz2ze76ybn73dvwmdij06zz ~]# cat guer.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
int main()
{
pid_t pid = fork();
if (pid < 0) {
perror("fork error;");
exit(1);
} else if (pid == 0) {
sleep(5);
printf ("子进程 : [ pid] = %d , 父进程 [ppid] = %d\n",getpid(),getppid());
exit(0);
} else if (pid > 0) {
printf("我是父线程,我先退出一步~\n");
exit(0);
}
return 0;
}
父进程退出后,子进程被ID=1的init进程领养了。每当有孤儿进程出现的时候,init进程就会收养它并成为它的父进程。
危害:
孤儿进程会被init进程接管,所以没有危害。
任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个 子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。 如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。
Z(ZOMBIE)僵尸进程
正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。
和孤儿进程相反,子进程先行退出,而父进程又没有处理回收释放的子进程的资源,这个时候子进程就成了僵尸进程。
危害
- 如果进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。
处理
- 干掉父进程
干掉父进程,让剩下的子进程变成孤儿进程,就会由init接管,并且处理这些进程的资源释放工作。
- 父进程调用wait 或 waitpid
特别注意,僵尸进程是不能使用 kill 命令清除掉的。因为 kill 命令只是用来终止进程的,而僵尸进程已经终止
等函数等待子进程结束,这会导致父进程挂起。执行wait()或 waitpid()系统调用,则子进程在终止后会立即把它在进程表中的数据返回给父进程,此时系统会立即删除该进入点。