系统编程-进程-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\n", (long)getpid());

    pid = fork();
    if (pid < 0) {
        printf("fork error");
    }
    else if (pid == 0) { 	
        sleep(2);
	printf("pid: %ld,  ppid: %ld\n", (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\n", 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 \n", WEXITSTATUS(status));

    }else if(WIFSIGNALED(status)){
        printf("abnormal term: %d \n", WTERMSIG(status));

    }else if(WIFSTOPPED(status)){
        printf("stopped sig: %d \n", WSTOPSIG(status));

    }else{
        printf("unknow sig");
    }
}

int main(void)
{
    int status = 0;
    pid_t pid;
    printf("pid: %ld\n", (long)getpid());

    pid = fork();
    if (pid < 0) {
            printf("fork error");
    }
    else if (pid == 0) { 	
           sleep(2);
	   printf("pid: %ld,  ppid: %ld\n", (long)getpid(), (long)getppid());

           exit(3);
    }

    if (wait(&status) != pid) {
           printf("waitpid error");
    }
    else{
	   printf("status =%d\n", 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 \n", WEXITSTATUS(status));

    }else if(WIFSIGNALED(status)){
        printf("abnormal term: %d \n", WTERMSIG(status));

    }else if(WIFSTOPPED(status)){
        printf("stopped sig: %d \n", WSTOPSIG(status));

    }else{
        printf("unknow sig");
    }
}

int main(void)
{
    int status = 0;
    pid_t pid;
    printf("pid: %ld\n", (long)getpid());

    pid = fork();
    if (pid < 0) {
        printf("fork error");
    }
    else if (pid == 0) { 	
        sleep(2);
	printf("pid: %ld,  ppid: %ld\n", (long)getpid(), (long)getppid());

        // 我们可以在子进程内新增几行除零运算的代码,来引发子进程异常终止
        int i=89, j=0;
        int k = i/j;
        printf("k=%d \n", k);

        exit(3);
    }

    if (wait(&status) != pid) {
        printf("waitpid error");
    }
    else{
	printf("status =%d\n", 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 \n", WEXITSTATUS(status));

    }else if(WIFSIGNALED(status)){
        printf("abnormal term: %d \n", WTERMSIG(status));

    }else if(WIFSTOPPED(status)){
        printf("stopped sig: %d \n", WSTOPSIG(status));

    }else if(WIFCONTINUED(status)){
	printf("WIFCONTINUED \n");
    }else{
        printf("unknow sig \n");
    }
}

int main(void)
{
    int status = 0;
    pid_t pid;
    printf("pid: %ld\n", (long)getpid());

    pid = fork();
    if (pid < 0) {
        printf("fork error");
    }
    else if (pid == 0) { 
	int i=0;
	printf("--child process begins running, pid=%d\n", getpid());	
        while(1){
	   i++;
	   if(i == 1000000)
		i=0;
        }
    }  

    pid = waitpid(pid, &status, WUNTRACED);
    printf("pid=%d \n", pid);
    out_status(status);

    pid = waitpid(pid, &status, WCONTINUED);
    printf("pid=%d \n", pid);
    out_status(status);	

    return 0;
}

 运行:

一个终端内:

另一个终端内:

分析:

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

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

补充:

19) SIGSTOP 20) SIGTSTP

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

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

 

 

 

.

posted @ 2021-03-07 21:21  一匹夫  阅读(2227)  评论(0编辑  收藏  举报