僵屍進程


fork和僵屍進程

 

1. 關於fork

fork()函數:

   用於創建一個進程,所創建的進程復制父進程的代碼段/數據段/BSS段/堆/棧等所有用戶空間信息;在內核中操作系統重新為其申請了一個PCB,並使用父進程的PCB進行初始化;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <unistd.h>
using  namespace  std;
int  val = 10;
int  main( int  argc,  char  *argv[])
{
     pid_t pid;
     int  lval = 20;
     pid = fork();
     if (pid == 0){
         val += 2;
         lval += 5;
     } else {
         val -= 2;
         lval += 5;
     }
     if (pid == 0){
         cout <<  "val:"  << val <<  ", lval = "  << lval << endl;
     } else {
         cout <<  "val:"  << val <<  ", lval = "  << lval << endl;
     }
     return  0;
}

對於父進程而言,fork()函數返回子進程的ID(子進程的PID);而對於子進程而言,fork函數返回0。

僵屍進程

  父進程創建子進程后,子進程運行到終止時刻(例如,調用exit()函數,或者運行到main中的return語句時,都會將返回的值傳遞給 操作系統),此時如果父進程還在運行,子進程並不會立即被銷毀,直到這些值傳到了產生該子進程的父進程。也就是說,如果父進程沒有主動要求獲得子進程的結束狀態值,操作系統就會一直保存該進程的相關信息,並讓子進程長時間處於僵屍狀態,例如下面程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int  main(){
     pid_t pid = fork();
     if (pid == 0){
         cout <<  "I am a Child Process."  <<endl;
     } else {
         cout <<  "I am a Father Process and Child Process is "  << pid << endl;
         sleep(30);   //讓父進程休眠30秒,此時便於觀察子進程的狀態
     }
     if (pid == 0){
         cout <<  " Child Process exits "  << endl;
     } else {
         cout <<  "Father Process exits "  << endl;
     }
     return  0;
}

此時,運行該程序,查看后台進程可知(test16是該測試程序的名稱,defunct表示僵屍進程):

復制代碼
gqx@gqx-Lenovo-Product:~$ ps -au
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root       923  0.6  0.9 480840 159824 tty7    Ssl+ 4月09  36:07 /usr/lib/xorg/
root      1351  0.0  0.0  17676  1768 tty1     Ss+  4月09   0:00 /sbin/agetty -
...
gqx      24856  0.0  0.0      0     0 pts/11   Z+   11:03   0:00 [tes16] <defunct>
gqx      24859  0.0  0.0  39104  3300 pts/3    R+   11:03   0:00 ps -au
復制代碼

僵屍進程的消除

方法一:調用wait()函數:

復制代碼
/* Wait for a child to die.  When one does, put its status in *STAT_LOC
   and return its process ID.  For errors, return (pid_t) -1.
​
   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern __pid_t wait (__WAIT_STATUS __stat_loc);
復制代碼

成功返回終止的進程ID,失敗返回-1;子進程的最終返回值將指向該函數參數所指向的內存空間,但函數所指向的內存單元總還含有其他的信息,需要使用宏進行分離。

# define WIFEXITED(status)  __WIFEXITED (__WAIT_INT (status))  //子進程正常終止返回"true"
# define WEXITSTATUS(status)    __WEXITSTATUS (__WAIT_INT (status)) //返回子進程的返回值

要注意的是:如果沒有已終止的子進程,那么程序將被阻塞,直到有子進程終止。

方法二:調用waitpid()函數

復制代碼
/* Wait for a child matching PID to die.
   If PID is greater than 0, match any process whose process ID is PID.
   If PID is (pid_t) -1, match any process.
   If PID is (pid_t) 0, match any process with the
   same process group as the current process.
   If PID is less than -1, match any process whose
   process group is the absolute value of PID.
   If the WNOHANG bit is set in OPTIONS, and that child
   is not already dead, return (pid_t) 0.  If successful,
   return PID and store the dead child's status in STAT_LOC.
   Return (pid_t) -1 for errors.  If the WUNTRACED bit is
   set in OPTIONS, return status for stopped children; otherwise don't.
​
   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern __pid_t waitpid (__pid_t __pid, int *__stat_loc, int __options);
復制代碼

第一個參數:如果__pid的值是-1,則與wait()函數相同,可以等待任意的子程序終止;如果是0,則等待進程組識別碼與目前進程相同的任何子進程;如果pid>0,則等待任何子進程識別碼為 pid 的子進程。

第二個參數:與前一個函數wait()的參數意義相同。

第三個參數:常用WNOHANG——若pid指定的子進程沒有結束,則waitpid()函數返回0,不予以等待。若結束,則返回該子進程的ID。

示例程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
using  namespace  std;
void  read_childproc( int  sig){
     int  status;
     pid_t id = waitpid(-1, &status, WNOHANG);
     if (WIFEXITED(status)){
         printf ( "Remove proc id: %d \n" , id);
         printf ( "Child send: %d \n" , WEXITSTATUS(status));
     }
}
int  main(){
     pid_t pid;
     struct  sigaction act;
     act.sa_handler = read_childproc;
     sigemptyset(&act.sa_mask);
     act.sa_flags = 0;
     sigaction(SIGCHLD, &act, 0);
     pid = fork();
     if (pid == 0){
         puts ( "Hi, I am a child process!" );
         sleep(6);
         return  12;
     } else {
         printf ( "Child proc id: %d \n" , pid);
         pid = fork();
         if (pid == 0){
             puts ( "Hi, I am a child process!" );
             sleep(13);
             exit (24);
         } else {
             int  i;
             printf ( "Child proc id: %d \n" , pid);
             for (i  = 0; i < 4; i++){
                 puts ( "wait..." );
                 sleep(5);
             }
         }
     }
     return  0;
}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM