zoukankan      html  css  js  c++  java
  • 系统编程-进程-wait、waitpid和WIFEXITED系列宏 超级详解

     

    1.  wait、waitpid 函数简介

    补充:对于waitpid,如果返回值为0,表示指定去等待的子进程尚未结束。

     

    该系列宏的使用方法展示:

     

    PART1

    实验思路:

    使用wait系统调用让父进程给子进程收尸,并获取子进程的返回值。

    同时,正常终止。

    直接打印获取的返回值会与实际返回的值不一样,进而引出检查WIFEXITED/WEXITSTATUS(status)等系列宏。

     

    实验1: waitpid或waitpid,使用展示, 同时,直接使用printf打印出子进程的返回值

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    
    int main(void)
    {
        int status = 0;
        pid_t pid;
        printf("pid: %ld
    ", (long)getpid());
    
        pid = fork();
        if (pid < 0) {
            printf("fork error");
        }
        else if (pid == 0) { 	
            sleep(2);
    	printf("pid: %ld,  ppid: %ld
    ", (long)getpid(), (long)getppid());
    
            exit(3);
        }
    
        if (waitpid(pid, &status, 0) != pid) { //     if (wait(&status) != pid) {  这里也可以使用wait, 我这里对waitpid的使用也是阻塞方式的
            printf("waitpid error");
        }
        else{
    	printf("status =%d
    ", status);
        }
    
        return 0;
    }
    

    编译运行:

    可以看到,本实验中的waitpid在2秒后才返回,成功替子进程收尸。

    但是我们打印的status不对劲,我们的代码内子进程返回值是3, 打印的768是什么鬼? 于是我们做实验2,使用WIFEXITED/WEXITSTATUS(status)等系列宏。

     

    实验2: 在实验1的基础上新增使用WIFEXITED/WEXITSTATUS(status)等系列宏

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    
    void out_status(int status){
    
        if(WIFEXITED(status)){
            printf("normnal exit: %d 
    ", WEXITSTATUS(status));
    
        }else if(WIFSIGNALED(status)){
            printf("abnormal term: %d 
    ", WTERMSIG(status));
    
        }else if(WIFSTOPPED(status)){
            printf("stopped sig: %d 
    ", WSTOPSIG(status));
    
        }else{
            printf("unknow sig");
        }
    }
    
    int main(void)
    {
        int status = 0;
        pid_t pid;
        printf("pid: %ld
    ", (long)getpid());
    
        pid = fork();
        if (pid < 0) {
                printf("fork error");
        }
        else if (pid == 0) { 	
               sleep(2);
    	   printf("pid: %ld,  ppid: %ld
    ", (long)getpid(), (long)getppid());
    
               exit(3);
        }
    
        if (wait(&status) != pid) {
               printf("waitpid error");
        }
        else{
    	   printf("status =%d
    ", status);
               out_status(status);
        }
    
        return 0;
    }
    

    编译运行:

    到此为止,wait和waitpid的阻塞式的使用,以及子进程正常返回的实验,顺利完成。

    我们还需要判断子进程的异常终止、和判断子进程是否暂停了, 所以我们接着来完善这部分的知识体系。

     

    PART2

    子进程异常终止 - 实验:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    
    void out_status(int status){
    
        if(WIFEXITED(status)){
            printf("normnal exit: %d 
    ", WEXITSTATUS(status));
    
        }else if(WIFSIGNALED(status)){
            printf("abnormal term: %d 
    ", WTERMSIG(status));
    
        }else if(WIFSTOPPED(status)){
            printf("stopped sig: %d 
    ", WSTOPSIG(status));
    
        }else{
            printf("unknow sig");
        }
    }
    
    int main(void)
    {
        int status = 0;
        pid_t pid;
        printf("pid: %ld
    ", (long)getpid());
    
        pid = fork();
        if (pid < 0) {
            printf("fork error");
        }
        else if (pid == 0) { 	
            sleep(2);
    	printf("pid: %ld,  ppid: %ld
    ", (long)getpid(), (long)getppid());
    
            // 我们可以在子进程内新增几行除零运算的代码,来引发子进程异常终止
            int i=89, j=0;
            int k = i/j;
            printf("k=%d 
    ", k);
    
            exit(3);
        }
    
        if (wait(&status) != pid) {
            printf("waitpid error");
        }
        else{
    	printf("status =%d
    ", status);
            out_status(status);
        }
    
        return 0;
    }
    

    编译运行,同时查看下8号信号是什么信号

    由度娘知,SIGFPE是系统发出的针对进程内进行非法运算的一个信号

    至此,我们又多了一个技能,可以判断子进程是否被异常终止,以及具体的异常终止原因了!

     

     

    PART3

    判断子进程是否暂停了

    要判断子进程是否暂停了,不能使用wait,只能使用waitpid,而且需要加上特定的参数选项。

    重申下列知识点:

    由此可见,

    waitpid函数的最后一个参数配置为WUNTRACED,则后续判断子进程返回状态时,需要结合WIFSTOPED宏、

    waitpid函数的最后一个参数配置为WCONTINUED,则后续判断子进程返回状态时,需要结合WIFCONTINUED宏。

     

    实验环节

    实验目的:判断子进程是否暂停了、是否又继续运行起来了

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    
    void out_status(int status){
    
        if(WIFEXITED(status)){
            printf("normnal exit: %d 
    ", WEXITSTATUS(status));
    
        }else if(WIFSIGNALED(status)){
            printf("abnormal term: %d 
    ", WTERMSIG(status));
    
        }else if(WIFSTOPPED(status)){
            printf("stopped sig: %d 
    ", WSTOPSIG(status));
    
        }else if(WIFCONTINUED(status)){
    	printf("WIFCONTINUED 
    ");
        }else{
            printf("unknow sig 
    ");
        }
    }
    
    int main(void)
    {
        int status = 0;
        pid_t pid;
        printf("pid: %ld
    ", (long)getpid());
    
        pid = fork();
        if (pid < 0) {
            printf("fork error");
        }
        else if (pid == 0) { 
    	int i=0;
    	printf("--child process begins running, pid=%d
    ", getpid());	
            while(1){
    	   i++;
    	   if(i == 1000000)
    		i=0;
            }
        }  
    
        pid = waitpid(pid, &status, WUNTRACED);
        printf("pid=%d 
    ", pid);
        out_status(status);
    
        pid = waitpid(pid, &status, WCONTINUED);
        printf("pid=%d 
    ", pid);
        out_status(status);	
    
        return 0;
    }
    

     运行:

    一个终端内:

    另一个终端内:

    分析:

    先向子进程发送19号信号,会使得父进程解除阻塞,获取到子进程被暂停了这一信息。

    之后父进程又再次调用阻塞接口,等待子进程继续运行,当在该终端内发送18号信号,即可让子进程继续运行,从而使得父进程解除阻塞,获得子进程又继续运行了这一信息。

    补充:

    19) SIGSTOP 20) SIGTSTP

    19号信号和29号信号的相同点: 都可以使得进程暂停,并且收到SIGCONT信号后可以让进程重新运行。

    19号信号和29号信号的不同点:    SIGSTOP不可以捕获(即使用信号处理函数)。

     

     

    .

    /************* 社会的有色眼光是:博士生、研究生、本科生、车间工人; 重点大学高材生、普通院校、二流院校、野鸡大学; 年薪百万、五十万、五万; 这些都只是帽子,可以失败千百次,但我和社会都觉得,人只要成功一次,就能换一顶帽子,只是社会看不见你之前的失败的帽子。 当然,换帽子决不是最终目的,走好自己的路就行。 杭州.大话西游 *******/
  • 相关阅读:
    springMVC中添加<mvc:resource>时的问题
    package
    mybatis 解决属性名和字段名不一致
    Linux常用命令
    Hibernate下载
    Hibernate初识
    js根据身份证获取出生年月日
    spring-Boot 热部署
    Struts2---动态action以及应用
    Struts2基础
  • 原文地址:https://www.cnblogs.com/happybirthdaytoyou/p/14496476.html
Copyright © 2011-2022 走看看