linux进程关系操作

本文介绍了Linux中如何使用wait、waitpid、wait3和wait4函数管理子进程,包括等待子进程结束、避免僵尸进程产生及获取进程资源使用情况的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.等待进程退出

linux中利用wait函数得到子进程的结束信息,其函数原型如下:

 

#include <sys/wait.h>

pid_t wait(int * statloc);

 

调用wait的函数会阻塞,直到该进程的任意一个子进程结束。wait会取得结束的子进程的信息并且返回该子进程的进程ID,结婚诉信息保存在参数statloc中。如果该进程没有子进程,则立即出错返回,返回值为-1;如果在调用wait函数时已经有若干个子进程结束运行了,则wait函数立即返回,但是具体取得的是哪一个子进程的信息则是不定的,需要根据wait函数的返回值来判断。

 

 

                                                                           进程终止信息和操作宏

状态                                                   判断宏                                               取值宏

进程正常结束                                   WIFEXITED(status)                   WEXITSTATUS(status)

进程异常终止                                   WIFSIGNALED(status)             WTERMSIG(status)

进程暂停                                           WIFSTOPPED(status)              WSTOPSIG(status)

 

例如,当一个进程正常退出时,该进程的父进程得到其结束信息,则需判断:如果WIFEXITED(status)值为真,那么说明该进程正常退出,WEITSTATUS(status)使用返回信息中进程结束状态。

 

eg:

//wait.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
 
int main(void)
{
    pid_t pid;
    int status;
 
    pid = fork( );
    if(pid < 0){
        perror("fail to fork");
        exit(1);
    }else if(pid == 0){
        printf("the first, exit normally/n");
        exit(0);
    }else{   /*父进程*/
        if(wait(&status) == -1){
            perror("fail to wait");
            exit(1);
        }
 
        if(WIFEXITED(status) == 1)    /*正常退出*/
            printf("the status of first is : %d/n", WEXITSTATUS(status));
    }
     
    pid = fork();
    if(pid < 0){
        perror("fail to fork");
        exit(1);
    }else if(pid == 0){
        printf("the second, exit abnormally/n");
        1 / 0;  /*会产生SIGFPE异常信号*/
    }else{   /*父进程*/
        if(wait(&status) == -1){
            perror("fail to wait");
            exit(1);
        }
 
        if(WIFSIGNALED(status) == 1)   /*得到终止子进程的信号的值*/
            printf("the terminated signal is : %d/n", WTERMSIG(status));
    }
 
    return 0;
}

 

2.等待指定的进程

wait只能等待第一个结束的子进程如果需要指定等待一个子进程则需要使用如下代码实现:

 

while(pid!=wait(&status));

 

这里还有另一个函数:

 

#include <sys/wait.h>

pid_t waitpid(pid_t pid,int * statloc,int options);

 

pid指定要等待的子进程的进程ID,其还有一些其他作用

 

pid                                          等待的作用

-1                                            等待任意子进程

>0                                           等待进程id和pid相等的子进程

0                                             等待组id和pid相等的子进程

<-1                                          等待组id等于pid绝对值的组内的任意子进程

 

statloc的含义同wait中的

 

第三个是控制选项。

wait函数选项                         选项说明

WCONTINUED                     当子进程在暂停后继续执行,且其状态尚未报告,则返回其状态

WNOHANG                           当所等待进程尚未结束运行时不阻塞,waitpid函数直接返回

WUNTRACED                      当子进程暂停时,并且其状态自暂停以来还未报告国,则返回其状态

该参数可以是0,也可以是上面所述的3种选项“或”得到。

waitpid函数等待指定的子进程,如该子进程已结束运行,返回值是子进程的进程id。此时若pid>0则返回值等于参数pid的值;如果该进程尚未结束,且设置了WNOHANG选项,则返回值为-1,如果指定进程或者进程组不存在或者参数pid所指定的进程不是调用waitpid函数的进程的子进程,则立即出错返回-1。

 

eg:

//waitpid.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
pid_t pid;

pid=fork();

if(pid<0){
printf("fail to fork/n");
exit(1);
}else if(pid==0){
printf("the child/n");
sleep(5);
exit(0);
}else{
printf("the parent/n");
if(waitpid(pid,NULL,WNOHANG)==-1)  /*非阻塞等待子进程*/
printf("the child is not available now/n");
}

printf("no waiting,parent done/n");
return 0;
}

 

3.僵尸进程

子进程已经退出了,但是它的退出状态信息仍然保存在内核中,进程的的id也保存在系统的进程列表中。这时的进程成为僵尸进程。

它不能代行,也不会占用cpu时间。

僵尸进程会一直存在于系统中,直到父进程得到其结束状态信息(即父进程调用wait)。

因为僵尸进程仍然占用着ID,所以若僵尸进程达到一定的数目时,系统中将不能再产生新的进程。

 

eg:

//zombie.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
int main(void)
{
    pid_t pid;
 
    pid = fork();
 
    if(pid < 0){
        printf("fail to fork/n");
        exit(0);
    }else if(pid == 0){
        printf("the child/n");
         
        sleep(5);
         
        printf("done/n");
        exit(0);
    }else
        printf("the parent/n");
     
    sleep(30); /*在这30秒的时间内,子进程是一个僵尸进程*/
 
    if(wait(NULL) == -1){
        perror("fail to wait");
        exit(1);
    }
 
    return 0;
}

 

4.避免僵尸进程的产生

为了避免僵尸进程的产生,必须在父进程中调用wait函数,但是,考虑一个处理交互式客户端请求的服务器程序模型:

 

socket();

bind();

listen();

while(1){

  accept();

  if(fork()==0){ //创建一个子进程处理客户端的交互式请求

    while(1){

      read();

      process();//处理请求

      write();

    }

    close();

    exit();

  }

  close();

}

 

如果父进程调用wait函数,那么在子进程退出之前父进程会阻塞。因此,服务器一次只能处理一个客户端的请求。

 

如果父进程自子进程结束前结束运行,这是的子进程成为孤儿进程。init进程负责领养所用的孤儿进程,也就是说init进程会成为所有父进程先于自己退出的进程的父进程。作为系统的一个守护进程,init进程被设计成为永远调用wait函数,也就是说init进程的所有的子进程都不会成为僵尸进程。因此就用这种方法避免产生僵尸进程。

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
 
int main(void)
{
    pid_t pid;
 
    pid = fork();
 
    if(pid < 0){
        printf("fail to fork/n");
        exit(1);
    }else if(pid == 0){
        printf("the child/n");
         
        pid = fork(); //创建一个孙子进程,这个进程负责处理实际工作
         
        if(pid < 0){
            printf("fail to fork/n");
            exit(1);
        }else if(pid == 0){//孙子进程
            printf("do something you want/n");
             
            sleep(5);
             
            printf("done/n");
            exit(0);
        }else
            exit(0);//子进程退出,将孙子进程托付给init进程
    }else
        printf("the parent/n");
       
        if(wait(NULL)==-1){ //父进程调用wait
                perror("fail to wait");
                exit(1);
        }
 
    return 0;
}

 

使用这种方法,上述的服务器模型变为如下的形式:

 

socket();

bind();

listen();

while(1)

  accept();

  if(fork()==0){

    if(fork()==0){//创建孙子进程

      while(1){

        read()

        process();

        write();

      }

      close();

      exit();

      }else

        exit();  //子进程退出,孙子进程的父进程变成init进程

   }

   close();

}

 

 

5.输出进程的统计信息

要得到进程执行中的更多信息(如进程的cpu使用量,页面出错次数等),可以使用wait3和wait4函数,它们分别类似于wait和waitpid函数。

 

#include <sys/types.h>

#include <sys/wait.h>

#include <sys/time.h>

#include <sys/source.h>

 

pid_t wait3(int *statloc,int options,struct rusage * rusage);

pid_t wait4(pid_t pid,int *statloc,int options,struct rusage * rusage);

 

更详细的信息保存在rusage中。

 

//wait3.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/resource.h>
 
int main(void)
{
    pid_t pid;
    struct rusage rusage;
 
    pid = fork();
 
    if(pid < 0){
        printf("fail to fork/n");
        exit(0);
    }else if(pid == 0){
        printf("the child/n");
         
        exit(0);
    }else
        printf("the parent/n");
     
    if(wait3(NULL, 0, &rusage) == -1){
        perror("fail to wait");
        exit(1);
    }
 
    printf("utime is %d", rusage.ru_utime);
    printf("stime is %d", rusage.ru_stime);
    printf("maxrss is %d", rusage.ru_maxrss); 
    printf("ixrss is %d", rusage.ru_ixrss); 
    printf("idrss is %d", rusage.ru_idrss);
    printf("isrss is %d", rusage.ru_isrss);
    printf("minflt is %d", rusage.ru_minflt);
    printf("majflt is %d", rusage.ru_majflt);
    printf("nswap is %d", rusage.ru_nswap);
    printf("inblock is %d", rusage.ru_inblock);
    printf("oublock is %d", rusage.ru_oublock);
    printf("msgsnd is %d", rusage.ru_msgsnd);
    printf("msgrcv is %d", rusage.ru_msgrcv);
    printf("nsignals is %d", rusage.ru_nsignals);
    printf("nvcsw is %d", rusage.ru_nvcsw);
    printf("nivcsw is %d", rusage.ru_nivcsw);
 
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值