进程的状态/僵尸进程/进程等待

目录

 

Linux进程状态

僵尸进程的避免

进程等待

为什么需要进程等待?

进程等待wait()

进程等待waitpid()

对于wait和waitpid两个函数,有所不同的是:

注意事项:


Linux进程状态

Linux进程状态:R (TASK_RUNNING),可执行状态。

只有在该状态的进程才可能在CPU上运行。但并不一定在运行中,表示要么在运行中,要么在运行队列里.一个进程最多只能出现在一个CPU的可执行队列中。进程调度器的任务就是从各个CPU的可执行队列中分别选择一个进程在该CPU上运行

Linux进程状态:S (TASK_INTERRUPTIBLE),可中断的睡眠状态。

等待事件的完成

Linux进程状态:D (TASK_UNINTERRUPTIBLE),不可中断的睡眠状态。

通常在等待IO的结束

Linux进程状态:T (TASK_STOPPED or TASK_TRACED),暂停状态或跟踪状态。

向进程发送一个SIGSTOP信号,它就会因响应该信号而进入TASK_STOPPED状态.向进程发送一个SIGCONT信号,可以让其从TASK_STOPPED状态恢复到TASK_RUNNING状态

Linux进程状态:Z (TASK_DEAD - EXIT_ZOMBIE),退出状态,进程成为僵尸进程。

进程在退出的过程中,处于TASK_DEAD状态。在这个退出过程中,进程占有的所有资源将被回收,除了task_struct结构(以及少数资源)以外。于是进程就只剩下task_struct这么个空壳,故称为僵尸。之所以保留task_struct,是因为task_struct里面保存了进程的退出码、以及一些统计信息。而其父进程很可能会关心这些信息

用下面的命令找出僵死进程

ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]'

僵尸进程的避免

⒈父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起。

⒉ 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后, 父进程会收到该信号,可以在handler中调用wait回收。

⒊ 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD,SIG_IGN) 通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收, 并不再给父进程发送信号。

⒋ 还有一些技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程fork一 个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收 还要自己做。

Linux进程状态:X (TASK_DEAD - EXIT_DEAD),退出状态,进程即将被销毁。

进程将被置于EXIT_DEAD退出状态,这意味着接下来的代码立即就会将该进程彻底释放。所以EXIT_DEAD状态是非常短暂的,几乎不可能通过ps命令捕捉到

进程等待

为什么需要进程等待?

一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息

如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或者waitpid获取这些信息,然后彻底清除掉这个进程.

当它终止是Shell调用wait或waitpid得到它的退出状态同时彻底清除掉这个进程。

当一个进程正常或异常终止时,内核就向其父进程发生发送一个SIGCHILD信号。

因为子进程终止是一个异步事件,所以发生这种信号也是内核向父进程发出的异步通知。

父进程可以选择忽略该信号,或者提供一个信号发生时即被调用执行的函数。

对于这种信号的系统默认动作是忽略它。现在需要知道的是wait或者waitpid的进程可能会发生什么情况:

  1. 如果其所有子进程都还在运行,则阻塞(options参数传0)
  2. 如果一个进程已经终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。
  3. 如果它没有任何子进程,则立即出错返回。

进程等待wait()

进程的状态/僵尸进程/进程等待

wait()函数用于使父进程(也就是调用wait()的进程)阻塞,直到一个子进程结束或者该进程接收到了一个指定的信号为止。如果该父进程没有子进程或者它的子进程已经结束,则wait()函数就会立即返回。

进程的状态/僵尸进程/进程等待

进程等待waitpid()

进程的状态/僵尸进程/进程等待

对于wait和waitpid两个函数,有所不同的是:

  1. 如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而调用waitpid时如果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。
  2. wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程。

注意事项:

如果子进程已经退出,调用wait( )/waitpid()会立即返回,并且获得子进程的退出信息,并且释放资源

如果在任意时刻调用wait()/waitpid(),子进程存在并且在正常运行,则进程可能会阻塞

如果不存在该进程,则会出错返回.