上一节最后我们说到若子进程先于父进程结束时,父进程调用wait()函数和不调用wait()函数会产生两种不同的结果:

--如果父进程没有调用wait()和waitpid()函数,子进程就会进入僵死状态。

--如果父进程调用了wait()和waitpid()函数,就不会使子进程变为僵尸进程。

这是为什么呢?现在我们来深入学习wait()函数和waitpid()函数。

一.wait()和waitpid()学习

1.首先我们先看一下它们的函数原型:

在终端输入命令:man 2 wait

就会看到它的函数原型:

NAME

wait, waitpid, waitid - wait for process to change state

SYNOPSIS

#include

#include

pid_t wait(int *status);

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

int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

我们可以看到在2.6版本中新增叫了waitid()函数。

2.wait()和waitpid()的功能:

1>wait()函数使父进程暫停执行,直到它的一个子进程结束为止,该函数的返回值是终止运行的子进程的PID. 参数status所指向 的变量存放子进程的退出码,即从子进程的main函数返回的值或子进程中exit()函数的参数。如果status不是一个空指针,状态信息将被写入它指向的变

量。

2> 头文件sys/wait.h中定义了进程退出状态的宏。

我们首先看下官方的解释

a.WIFEXITED(status)     r eturns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main() .

Tiger-John翻译:

WIFEXITED(status)  若子进程是正常结束时则返回一个非零值。即调用exit(3),_exit(3) 或从main()函数返回的值。

b. WEXITSTATUS(status)   returns the exit status of the  child.   This  consists  of  the least  significant  8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) or  as  the  argument for  a return  statement  in main().  This macro should only be employed if WIFEXITED returned true.

Tiger-John翻译:

WEXITSTATUS(status)    如果宏 WIFEXIED返回值为非零值时,它返回子进程中exit或_exit参数中的低8位。

c.W IFSIGNALED(status)  returns true if the child process was terminated by a signal.

Tiger-John翻译:

WIFSIGNALED(status)  若子进程异常终止则返回一个非零值。

d. WTERMSIG(status)   returns the number of the signal that caused the  child  process  to terminate.  This macro should only be employed if WIFSIGNALED returned true.

Tiger-John翻译:

WTERMSIG(status)      如果宏WIFSIGNALED的返回值非零,则返回使子进程异常终止的信号编号。

e.WIFSTOPPED(status)   returns true if the child process was stopped by delivery  of a signal;  this  is  only possible if the call was done using WUN‐TRACED or when the child is being traced (see ptrace(2)).

Tiger-John翻译:

WIFSTOPPED(status)  若子进程由于异常暫停,则返回一个非零值。当调用 WUN‐TRACED或子进程被跟踪时这才时可能的。

f. WSTOPSIG(status)    returns the number of the signal which caused the child to stop.This macro should only be employed if WIFSTOPPED returned true.

Tiger-John翻译:

WSTOPSIG(status)      如果宏WIFSTOPPED返回值非零,则返回使子进程暫停的信号编号。

g.WIFCONTINUED(status)     (since  Linux  2.6.10)  returns  true  if  the child process was

resumed by delivery of SIGCONT.

Tiger-John翻译:

WIFCONTINUED(status)     (从2.6版本后)如果孩子进程通过SIGCONT恢复则返回一个非零

值。

3>waitpid() 函数

(1)我们先来看一个waitpid()的经典例子:当我们下载了A软件的安装程序后,在安装快结束时它又启动了另外一个流氓软件安装程序B,当B也安装结束后,才告诉你所有安装都完成了。A和B分别在不同的进程中,A如何启动B并知道B安装完成了呢?可以很简单地在A中用fork启动B,然后用 waitpid()来等待B的结束。

(2)waitpid()也用来等待子进程的结束,但它用于等待某个特定进程结束。参数pid指明要等待的子进程的PID,参数 status的含义与wait()函数中的 status相同。options参数可以用来改变waitpid的行为,若将该参数赋值为WNOHANG,则使父进程不被挂起而立即返回执行其后的代

码。

(3)waitpid()函数中参数pid的取值

还是先看下官方解释:

The value of pid can be:

< -1   meaning  wait  for  any  child process whose process group ID is

equal to the absolute value of pid.

-1     meaning wait for any child process.

0      meaning wait for any child process whose  process  group  ID  is

equal to that of the calling process.

> 0    meaning  wait  for  the  child  whose process ID is equal to the

value  of pid.

Tiger-John翻译:

pid的值可以为下己中情况:

< -1  等待其组ID等于pid绝对值的任一子进程。

=-1  等待任一子进程

=0 等待其组ID等于调用进程的组ID的任一进程

> 0  等待其进程ID等于pid的子进程退出

(4)waitpid()函数的一个应用:

如果想让父进程周期性地检查某个特定的子进程是否已经退出,可以用下面的方法:

waitpid(child_pid,(int *) 0,WNOHANG);

如果子进程尚未退出,它将返回0;如果子进程已经结束,则返回child_pid。调用失败时返回-1。失败的原因包括没有该子进程,参数不合法等。

3.wait()和 waitpid() 函数的区别

(1). 在一个子进程终止前,wait()使其调用者阻塞,而waitpid()有一个选项,可使调用者不阻塞。

(2). waitpid()并不等待在其调用之后的第一个终止子进程,它有若干个选项,可以控制它所等待的进程。

(3). 对于wait(),其唯一的出错是调用进程没有子进程;对于waitpid(),若指定的进程或进程组不存在,或者参数pid指定的进程不是调用进程的子进程都可能出错。

(4). waitpid()提供了wait()没有的三个功能:一是waitpid()可等待一个特定的进程;二是waitpid()提供了一个wait()的非阻塞版本(有时希望取的一个子进程的状态,但不想使父进程阻塞,waitpid() 提供了一个这样的选择:WNOHANG,它可以使调用者不阻塞);三是waitpid()支持作业控制。

(5)  wait(&status) 的功能就等于waitpid(-1, &status, 0);

函数实例: 有时希望取的一个子进程的状态,但不想使父进程阻塞,waitpid() 提供了一个这样的选择:WNOHANG,它可以使调用者不阻塞

/* 如果是父进程 */

do{

pr=waitpid(pc, NULL, WNOHANG);

/* 使用了WNOHANG参数,waitpid不会在这里等待 */

if(pr==0){            /* 如果没有收集到子进程 */

rintf("No child exited\n");

sleep(1);

}

}while(pr==0);    /* 没有收集到子进程,就回去继续尝试 */

if(pr==pc)

printf("successfully get child %d\n", pr);

else

printf("some error occured\n");

Tiger-John总结

无论进程是否正常终止,内核都会向其父进程发送SIGCHLD 信号, 当调用wait或waitpid函数时

(a) 如果所有的子进程都在run, 可以阻塞父进程。

(b) 如果子进程终止,则wait立即返回子进程终止状态。

(c) 如果没有子进程在运行, 立即返回error。

4.函数实现:

函数实例 1.(先看一个简单的实例,看看进程调用wait()函数后是如何执行的?)

1 #include

2 #include

3 #include

4 #include

5 #include

6

7 int main()

8 {

9         pid_t child;

10         int i;

11         child = fork();

12         if(child < 0){

13                 printf("create failed!\n");

14                 exit(1);

15         }

16         else if (0 == child){

17                 printf("this is the child process pid= %d\n",getpid());

18                 for(i = 0;i<5;i++){

19                         printf("this is the child process print %d !\n",i+1);

20                  }

21         printf("the child end\n");

22         }

23         else{

24                 printf("this is the father process,ppid=%d\n",getppid());

25                 printf("father wait the child end\n");

26                 wait(&child);

27                 printf("father end\n");

28         }

29

30

31 }

函数经过编译:

函数执行结果:

this is the father process,ppid=3303

father wait the child end

this is the child process pid= 3356

this is the child process print 1 !

this is the child process print 2 !

this is the child process print 3 !

this is the child process print 4 !

this is the child process print 5 !

the child end

father end

Tiger-John说明:

从上面的程序我们可以深入的了解wait() 函数的执行过程:

当父进程调用wait()函数后被挂起等待,直到子进程结束为止。

函数实例2(现在我们在通过一个实例,来深入了解wait()函数的执行过程)

1 #include

2 #include

3 #include

4 #include

5 #include

6 int main()

7 {

8         pid_t pid;

9         char *msg;

10         int i;

11         int exit_code;

12

13         printf("tiger study how to get exit code\n");

14         pid = fork();

15         if(0 == pid){

16                 msg = " child process is running";

17                 i = 5;

18                 exit_code = 37;

19         }

20         else if(pid >0){

21                 exit_code = 0;

22         }

23         else{

24                 perror("process creation failed\n");

25                 exit(1);

26         }

27         if(pid > 0){

28

29                 int status;

30                 pid_t child_pid;

31

32                 child_pid = wait(&status);

33

34                 printf("child process has exited,pid = %d\n",child_pid);

35                 if(WIFEXITED(status)){

36                         printf("child exited with code %d\n",WEXITSTATUS(status));

37                 }

38                 else{

39                         printf("child exited abnormally\n");

40                 }

41         }

42         else{

43                 while(i-- > 0){

44                         puts(msg);

45                         sleep(1);

46                 }

47         }

48 }

函数进过编译后:

函数执行结果 :

tiger study how to get exit code

child process is running

child process is running

child process is running

child process is running

child process is running

child process has exited,pid = 3816

child exited with code 0

Tiger-John说明:

父进程调用wait()函数后被挂起(我们可以再开一个终端,输入命令:ps aux,可以看到父进程的执行结果为S)直到子进程结束。子进程结束后,wait()函数返回刚刚结束运行的子进程的pid,宏WEXITSTATUS获取子进程的退出码。

linux的多进程等待,等待进程结束wait()和waitpid()函数相关推荐

  1. Linux 等待进程结束 wait() 和 waitpid()

    若子进程先于父进程结束时,父进程调用wait()函数和不调用wait()函数会产生两种不同的结果: --> 如果父进程没有调用wait()和waitpid()函数,子进程就会进入僵死状态. -- ...

  2. linux shell 指定端口 杀进程 结束进程

    kill -9 $(netstat -antp | grep :8080 | awk '{print $7}' | awk -F'/' '{ print $1 }') 其中 netstat -antp ...

  3. 【Linux】linux进程--进程控制:进程创建、进程终止、进程等待、进程程序替换

    目录 1.进程创建 1)重温fork():让正在运行的进程创建出来一个子进程:从已存在的进程中创建一个新的进程,新进程为子进程而远进程为父进程. 2)fork内部完成的事情 3)用户空间 & ...

  4. linux 用户进程结束后 malloc申请的内存会自动释放吗,进程退出后malloc的内存是否会被释放?

    当一个进程退出后,不管是正常退出或者是异常退出,操作系统都会释放这个进程的资源.包括这个进程分配的内存,打开的文件等等. 内存泄露的前提是进程一直在运行:进程一旦退出,所占的整个虚拟内存都被销毁,所有 ...

  5. linux 的多进程运行机制,Linux 多进程-2

    揭秘文件描述符的本质 1. 文件描述符的本质是数组元素的下标 右侧的表称为 i 节点表,在整个系统中只有1张.该表可以视为结构体数组,该数组的一个元素对应于一个物理文件. 中间的表称为文件表,在整个系 ...

  6. linux 线程异常退出_Linux 进程必知必会

    只是简单的描述了一下 Linux 基本概念,通过几个例子来说明 Linux 基本应用程序,然后以 Linux 基本内核构造来结尾.那么本篇文章我们就深入理解一下 Linux 内核来理解 Linux 的 ...

  7. 【Linux系统编程】守护进程、线程

    ------------->[Linux系统编程/网络编程](学习目录汇总) <-------------- 目录 1.守护进程 1.1 进程组 1.2 会话 1.3 setsid()函数 ...

  8. linux C++ 多进程初步02

    ps:疑惑的地方,1 进程pcb的概念, 还有 ulimit -a 显示的信息 是一个进程可以最大占用资源的上限吗? 还有 文件描述符的概念?? 这里不是很明白!记录一下2还有WIFEXITED 孤儿 ...

  9. linux waitpid实例,Linux中waitpid()函数的用法

    大家知道,当用fork启动一个新的子进程的时候,子进程就有了新的生命周期,并将在其自己的地址空间内独立运行.但有的时候,我们希望知道某一个自己创建的子进程何时结束,从而方便父进程做一些处理动作.同样的 ...

最新文章

  1. PowerDesigner 使用的一些技巧(转)
  2. undefined reference to `libiconv_open 无法编译PHP
  3. 2022-02-21
  4. 通过C#/.NET API使用CNTK
  5. 前端学习(1804):前端调试之列表伪类
  6. springMVC 后端代码 如何用 @requestParam() 接收前台传过来的数组
  7. 二十六:Struts2 和 spring整合
  8. SVN—如何安装SVN服务器端软件
  9. leetcode56. Merge Intervals
  10. 【C++】常用拷贝算法和替换算法
  11. python token验证失败百分百解决_微信公众号token验证失败解决方案
  12. JSONObject.fromObject()方法报错解决方法
  13. 汽车品牌查询及车型大全查询
  14. 神经网络——单层感知器
  15. 网页无插件播放RTSP流媒体
  16. mysql 免安装版安装
  17. sqli-labs(23-27a)
  18. 【新书推荐】Interpretable Machine Learning with Python
  19. GPS脚环计步、AI“鸡”脸识别,如何确保自己吃到了一只幸福健康的鸡
  20. DataGridView 基本用法及注意事项

热门文章

  1. 桑拿lt是什么意思_lt是什么意思
  2. ppa:ondrej/php,现在为什么 Ubuntu ppa:ondrej/PHP 添加不了??
  3. dnf登录游戏自动连接服务器,游戏登录-新手引导-地下城与勇士官方网站-腾讯游戏...
  4. 家居行业供应链管理系统解决方案
  5. 基于 Verilog 的经典数字电路设计(13)并串转换器
  6. 云计算虚拟化技术总结
  7. 曾经风靡的1394接口是什么?有什么作用?
  8. Sqlserver2014远程远程连接
  9. 跟着楠哥学java(javase笔记)
  10. cocos2dx 安卓环境播放mid音乐