当前位置:   article > 正文

linux中进程相关概念(二)

linux中进程相关概念(二)

父进程等待子进程退出

我们创建子进程的目的,说白了就是让子进程为我们干活,干完活后会正常退出(exit),也有可能没干完异常退出(abort,或ctrl+c)。因此我们需要等待子进程退出,并收集退出状态。子进程退出状态不被收集会编程僵尸进程。


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

int main(){
        //pid_t getpid(void);
        pid_t pid;
        int cnt = 0;

        pid = vfork();

        if(pid > 0){
                while(1){
                        printf("%d\n",cnt);
                        printf("this is father process,father pid is:%d\n",getpid());
                        sleep(1);
                }
        }else if(pid == 0){
                while(1){
                        printf("this is son process,son pid is:%d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3){
                                exit(0);
                        }
                }
        }

        return 0;
}

  • 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

在这段代码中,我们只是调用exit(0)退出进程,而没有收集退出状态,因此这个进程会变为僵尸进程,我们可以通过查看进程状态来观察:
this is son process,son pid is:14192
this is son process,son pid is:14192
this is son process,son pid is:14192
3
this is father process,father pid is:14191
3
this is father process,father pid is:14191

CLC 14191 0.0 0.0 4160 428 pts/0 S+ 10:56 0:00 ./myPro
CLC 14192 0.0 0.0 0 0 pts/0 Z+ 10:56 0:00 [myPro]
CLC 14194 0.0 0.0 13588 940 pts/4 S+ 10:56 0:00 grep --color=auto myPro
父进程id为14191 状态为S+说明正在运行,而子进程id为14192,状态为Z+说明是僵尸进程。

wait函数

因此我们需要调用wait函数来收集退出状态,防止子进程变为僵尸进程:
#include <sys/types.h>
#include <sys/wait.h>

*pid_t wait(int status); //参数是一个指针,是一个地址
在父进程中调用wait函数,会让子进程先退出后父进程在开始运行。

status参数

NULL

当我们不关心子进程的退出码时,直接wait(NULL);即可
在父进程中加入wait(NULL);运行后结果:
this is son process,son pid is:14259
this is son process,son pid is:14259
this is son process,son pid is:14259
3
this is father process,father pid is:14258
3
this is father process,father pid is:14258
子进程的pid为14259,父进程pid为14258,之后去检查子进程的运行状态:
CLC 14258 0.0 0.0 4160 428 pts/0 S+ 11:08 0:00 ./myPro
CLC 14261 0.0 0.0 13588 936 pts/4 S+ 11:08 0:00 grep --color=auto myPro
可以看到子进程已经退出,不是僵尸进程了。

非空

子进程的退出状态放在它所指向的地址中。

WIFEXITED(status)

此时我们需要调用特定的宏去解析,如果为正常终止子进程返回的状态,则为真(1).对于这种情况可执行WEXITSTATUS(status),取子进程传送给exit,_exit或_Exit参数的低8位。

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

int main(){
        //pid_t getpid(void);
        pid_t pid;
        int cnt = 0;
        int status = 10;

        pid = fork();

        if(pid > 0){
       	 		wait(&status);
                printf("child process quit,WIFEXITED=%d,WEXITSTATUS=%d\n",WIFEXITED(status),WEXITSTATUS(status));
                while(1){
                        printf("this is father process,father pid is:%d\n",getpid());
                        sleep(1);
                }
        }else if(pid == 0){
                while(1){
                        printf("this is son process,son pid is:%d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3){
                                exit(3);
                        }
                }
        }

        return 0;
}

  • 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

运行结果:
this is son process,son pid is:14392
this is son process,son pid is:14392
this is son process,son pid is:14392
child process quit,WIFEXITED=1,WEXITSTATUS=3
this is father process,father pid is:14391

WIFSIGNALED(status)

若为异常终止子进程返回的状态,则为真(接到一个不捕捉的信号)。对于这种情况,可执行WTERMSIG(status),取使进程终止的信号编号。

waitpid

wait与waitpid的区别:wait使调用者阻塞,waitpid有一个选项,可以使调用者不阻塞
*pid_t waitpid(pid_t pid, int status, int options);

pid_t pid

pid == -1 等待任一子进程。就这一方面而言,waitpid和wait等效
pid > 0 等待其进程id与pid相等的子进程
通常使用pid > 0在父进程中,由fork创建的子进程的pid号就等于父进程fork的返回值
pid == 0 等待其组id等于调用进程组id的任一子进程
pid < -1 等待其组id等于pid绝对值的任一子进程

int options常量参数

WCONTINUED:若实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但其状态尚未报告,则返回其状态。
WNOHANG:若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时返回值为0
WUNTRACED:若某实现支持作业控制,而由pid指定的任一子进程已处于暂停状态,并且其状态自暂停以来还未报告过,则返回其状态。

使用wait时会阻塞父进程,先运行子进程。如果我们希望不阻塞父进程,可以将options改为WNOHANG:

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

int main(){
        //pid_t getpid(void);
        pid_t pid;
        int cnt = 0;
        int status = 10;

        pid = fork();

        if(pid > 0){
                while(1){
                        //wait(&status);
                        waitpid(pid,&status,WNOHANG);
                        printf("child process quit,WIFEXITED=%d,WEXITSTATUS=%d\n",WIFEXITED(status),WEXITSTATUS(status));
                        printf("this is father process,father pid is:%d\n",getpid());
                        sleep(1);
                }
        }else if(pid == 0){
                while(1){
                        printf("this is son process,son pid is:%d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3){
                                exit(3);
                        }
                }
        }

        return 0;
}

  • 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

运行结果:
this is father process,father pid is:14535
this is son process,son pid is:14536
this is father process,father pid is:14535
this is son process,son pid is:14536
两个进程同时运行,不会发生阻塞的情况。
但是此时我们查看进程运行状态可以发现,虽然我们调用waitpid读取的子进程退出状态,但是子进程仍然是Z+僵尸进程。因此就目前的学习情况来说,还是使用wait来收集退出状态比较好,在未来waitpid会有他自己的应用。

孤儿进程

父进程如果不等待子进程退出,在子进程之前就结束了自己的生命,此时子进程叫做孤儿进程。
linux为了避免系统存在过多孤儿进程,init进程(进程id=1)收留孤儿进程,变成孤儿进程的父进程。
我们可以使父进程比子进程先结束,让父进程只执行一段printf函数而子进程执行三次,打印观察子进程的父进程id(通过getppid()读取父进程的pid)的变化:

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

int main(){
        //pid_t getpid(void);
        pid_t pid;
        int cnt = 0;
        int status = 10;

        pid = fork();

        if(pid > 0){
                printf("this is father process,father pid is:%d\n",getpid());
        }else if(pid == 0){
                while(1){
                        printf("this is son process,son pid is:%d,my father pid is:%d\n",getpid(),getppid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3) exit(0);
                }
        }

        return 0;
}

  • 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

运行结果:
this is father process,father pid is:15583
this is son process,son pid is:15584,my father pid is:15583
this is son process,son pid is:15584,my father pid is:1
this is son process,son pid is:15584,my father pid is:1

可以看到父进程的pid为15583,最开始子进程的父进程pid还是15583,此时父进程还没有结束,之后父进程比子进程先结束了,那么子进程就变成了孤儿进程,被init进程收留,init进程的pid为1.

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/556438
推荐阅读
相关标签
  

闽ICP备14008679号