目录
0.阅读与引用
《LinuxC编程从入门到精通》wait3-WEXITSTATUS(status)相关内容
在书中搜索的keywords:
1.为什么要有wait系列函数
在多进程处理时,用户可能需要用到有关进程等待的操作,这种等待可以是进程组成员间的等待,也可以
是父进程对子进程的等待。通过前面的介绍,读者已经了解了父进程和子进程的概念,并已经掌握了系统
调用exit的用法,但可能很少有人意识到,在一个进程调用了exit之后,该进程并非马上就消失掉,而是
留下一个称为僵尸进程(Zombie)的数据结构。这时的处理方法之一就是使用进程等待的系统调用wait和
waitpid。
在Linux进程的5种状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执
行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收
集,除此之外,僵尸进程不再占有任何内存空间。
2.wait和waitpid
2.1 wait和waitpid的原型
两个函数的返回:若成功则返回进程ID,若出错则返回-1。进程一旦调用了wait,就立即阻塞自己,由
wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,
wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直
阻塞在这里,直到有一个出现为止。
参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果程序员对这个
子进程是如何死掉的毫不在意,而只想把这个僵尸进程消灭掉(事实上绝大多数情况下,程序员们都会这
样想),这时就可以设定这个参数为NULL,就像下面这样:
pid = wait(NULL);
如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返
回-1,同时errno被置为ECHILD。
2.2 wait和waitpid的区别
从本质上讲,waitpid和wait的作用是完全相同的,但waitpid多出了两个可由用户控制的参数pid和
options,从而为用户编程提供了一种更为灵活的方式。waitpid可以用来等待指定的进程,可以使进
程不挂起而立刻返回。参数pid用于指定所等待的进程,其取值及相应的含义如表8.1所示。
参数options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选
项,这是两个常数,可以用“|”运算符把它们连接起来使用,比如:
ret = waitpid(-1,NULL,WNOHANG|WUNTRACED);
如果不想使用它们,也可以把options设为0,如:
ret = waitpid(-1,NULL,0);
如果使用了WNOHANG参数调用waitpid,即使没有子进程退出,它也会立即返回,不会像wait那样永远等下
去。而WUNTRACED参数,由于涉及一些跟踪调试方面的知识,加之极少用到,这里就不进行过多的介绍,
有兴趣的读者可以自行查阅相关材料。
看到这里,聪明的读者可能已经看出了端倪——wait不就是经过包装的waitpid吗?没错,察看内核源码目
录>/include/unistd.h文件349~352行就会发现以下程序段:
2.3 waitpid中的status
另外,waitpid的返回值也要比wait稍微复杂一些,一共有3种情况:
● 当正常返回的时候,waitpid返回收集到的子进程的进程ID。
● 如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0。
● 如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在。
当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid就会出错返回,这
时errno被设置为ECHILD。
另外,对于参数status,当其值不为NULL时,wait就会把子进程退出时的状态取出并存入其中,这是
一个整数值(int),指出了子进程是正常退出还是被非正常结束的(一个进程也可以被其他进程用信
号结束,这将在第9章中进行介绍),以及正常结束时的返回值,或被哪一个信号结束的等信息。由于
这些信息被存放在一个整数的不同二进制位中,所以用常规的方法读取会非常麻烦,人们就设计了一
套专门的宏(macro)来完成这项工作,宏定义及其含义如表8.2所示,其中最常用的是
WIFEXITED(status)和WEXITSTATUS(status)两个宏。
虽然名字一样,但表8.2中的参数status并不同于wait唯一的参数——指向整数的指针status,而是
status指针所指向的那个整数,切记不要搞混了。
WIFEXITED(status) 这个宏用来指示子进程是否为正常退出,如果是,它会返回一个非零值,否则返
回零值。当WIFEXITED返回非零值时,可以使用WEXITSTATUS(status)这个宏来提取子进程的返回值,
比如如果子进程调用exit(5)退出,WEXITSTATUS(status)就会返回5:如果子进程调用exit(7),
WEXITSTATUS(status)就会返回7。有一点值得注意的是:如果进程不是正常退出的,也就是说,
WIFEXITED返回0,这个值就毫无意义。
3.wait3和wait4
Linux系统还提供了另外两个用于进程等待的调用——wait3和wait4系统调用。wait3和wait4函数分别相当
于wait和waitpid函数,但与wait和waitpid相比,wait3和wait4多一个结构指针参数rusage。它们的函数
原型如下:
wait3和wait4在以前的waitpid等函数的基础上增加了可以获取进程及其子进程所占用的resources的情况
的功能。参数rusage是一个结构指针,调用这两个函数时,如果rusage不为NULL,则关于子进程执行时的
相关信息将被写入该指针指向的缓冲区内。鉴于wait3和wait4的功能与上面讲到wait和waitpid的功能十分相似,这里就不再赘述。
4.man手册中的信息
waitpid(): on success, returns the process ID of the child whose state has changed; if
WNOHANG was specified and one or more child(ren) specified by pid exist,
but have not yet changed state, then 0 is returned. On error, -1 is returned.