- 浏览: 141471 次
文章分类
最新评论
当一个进程正常终止或异常终止时,内核就会向其父进程发送 SIGCHLD 信号,父进程对这种信号的默认动作是忽略它。可以使用 wait 和 waitpid 函数来获取子进程的终止状态。
通常调用这两个函数时:
* 如果其所有子进程都还在运行,则阻塞。
* 如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态后立即返回。
* 如果它没有任何子进程,则立即出错返回。
这两个函数的区别如下。
(1)在一个子进程终止前,wait 使其调用者阻塞,而 waitpid 有一选项可使调用者不阻塞。
(2)waitpid 并不一定要等待在其调用之后的第一个终止子进程,它有若干个可以控制它所等待的进程的选项。
(3)对于 wait,其唯一的出错是调用进程没有子进程(函数调用被一个信号中断时也可能返回另一种出错)。但对于 waitpid,如果指定的进程或进程组不存在,或者 pid 指定的进程不是调用进程的子进程,都可能出错。
它们的参数 statloc 如果不是一个空指针,则子进程的终止状态就存放在它所指向的单元内。如果不关心终止状态,则可将其指定为空指针。依照传统,返回的整型状态字是由实现定义的,其中某些位表示退出状态(正常返回),其他位则指示信号编号(异常返回),有一位指示是否产生了 core 文件等。终止状态可用 <sys/wait.h> 中的各个宏来查看,下表中 4 个互斥的宏可用来取得进程终止的原因。基于这 4 个宏中哪一个为真,就可选用其它宏来取得退出状态、信号编号等(很多平台都支持 WCOREDUMP 宏,但如果定义了 _POSIX_C_SOURCE 常量,有些平台就隐藏该定义)。
下面这个程序就是利用这 4 个宏来打印进程终止状态的说明。
运行结果如下。
如果一个进程有几个子进程,那么只要有一个子进程终止,wait 就返回。如果要等待一个指定的进程终止,waitpid 函数就派上用场了。对于 waitpid 函数中的 pid 参数的作用解释如下。
* pid == -1:等待任一子进程,此时等效于 wait。
* pid > 0:等待进程 ID 为 pid 的子进程。
* pid == 0:等待组 ID 等于调用进程组 ID 的任一子进程。
* pid < -1:等待组 ID 等于 pid 绝对值的任一子进程。
参数 options 可以进一步控制 waitpid 的操作。此参数可以为 0 或者是下表中各常量按位或运算的结果(FreeBSD 8.0 和 Solaris 10 支持另一个非标准的可选常量 WNOWAIT,它使系统将终止状态已由 waitpid 返回的进程保持在等待状态,这样它可被再次等待)。
如果一个进程 fork 了一个子进程,但不要它等待子进程终止,也不希望子进程处于僵死状态直到父进程终止,实现这一要求的诀窍就是调用 fork 两次,正如下列这个程序所示。
执行结果:
注意,这里当原先的进程(即 exec 本程序的进程)终止时,shell 打印其提示符,因为这在第二个子进程打印其父进程 ID 之前发生。
另外,Single UNIX Specification 包含了另一个取得进程终止状态的函数----waitid,此函数类似于 waitpid,但提供了更多的灵活性。
waitid 也允许一个进程指定要等待的子进程,但它使用两个单独的参数表示要等待的进程所属的类型,而不是将此与进程 ID 或进程组 ID 组合成一个参数。id 参数的作用与 idtype 的值相关。该函数支持下表中的这几个 idtype 类型。
options 参数是下表中各标志的按位或运算,这些标志指示调用者关注哪些状态变化。
注意,WCONTINUED、WEXITED 和 WSTOPPED 这 3 个常量之一必须指定。
infop 参数是指向 siginfo 结构的指针,该结构包含了造成子进程状态改变有关信号的详细信息。
大多数 UNIX 系统实现还提供了 wait3 和 wait4 函数,它们提供的功能比上面几个 wait 函数提供的要多一个,这与附加参数有关,该参数允许内核返回由终止进程及其所有子进程使用的资源情况。资源统计信息(不同于资源限制)包括用户 CPU 时间总量、系统 CPU 时间总量、缺页次数、接收到信号的次数等,有关细节可查阅 getrusage(2) 手册页。
#include <sys/wait.h> pid_t wait(int *statloc); pid_t waitpid(pid_t pid, int *statloc, int options); /* 两个函数返回值:若成功,返回进程 ID;否则,返回 0 或 -1 */
通常调用这两个函数时:
* 如果其所有子进程都还在运行,则阻塞。
* 如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态后立即返回。
* 如果它没有任何子进程,则立即出错返回。
这两个函数的区别如下。
(1)在一个子进程终止前,wait 使其调用者阻塞,而 waitpid 有一选项可使调用者不阻塞。
(2)waitpid 并不一定要等待在其调用之后的第一个终止子进程,它有若干个可以控制它所等待的进程的选项。
(3)对于 wait,其唯一的出错是调用进程没有子进程(函数调用被一个信号中断时也可能返回另一种出错)。但对于 waitpid,如果指定的进程或进程组不存在,或者 pid 指定的进程不是调用进程的子进程,都可能出错。
它们的参数 statloc 如果不是一个空指针,则子进程的终止状态就存放在它所指向的单元内。如果不关心终止状态,则可将其指定为空指针。依照传统,返回的整型状态字是由实现定义的,其中某些位表示退出状态(正常返回),其他位则指示信号编号(异常返回),有一位指示是否产生了 core 文件等。终止状态可用 <sys/wait.h> 中的各个宏来查看,下表中 4 个互斥的宏可用来取得进程终止的原因。基于这 4 个宏中哪一个为真,就可选用其它宏来取得退出状态、信号编号等(很多平台都支持 WCOREDUMP 宏,但如果定义了 _POSIX_C_SOURCE 常量,有些平台就隐藏该定义)。
下面这个程序就是利用这 4 个宏来打印进程终止状态的说明。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> void pr_exit(int status){ if(WIFEXITED(status)) printf("normal terminaltion, exit status = %d\n", WEXITSTATUS(status) ); else if(WIFSIGNALED(status)) printf("abnormal termination, signal number = %d%s\n", WTERMSIG(status), #ifdef WCOREDUMP WCOREDUMP(status)?"(core file generated)": ""); #else ""); #endif else if(WIFSTOPPED(status)) printf("child stopped, signal number = %d\n", WSTOPSIG(status)); } int main(void){ pid_t pid; int status; if((pid=fork()) < 0){ printf("1st fork error\n"); exit(2); }else if(pid == 0) // child exit(7); if(wait(&status) != pid){ // wait for child printf("1st wait error\n"); exit(2); } pr_exit(status); // and print its status if((pid=fork()) < 0){ printf("2nd fork error\n"); exit(2); }else if(pid == 0) abort(); // generates SIGABRT, signal number is 6 if(wait(&status) != pid){ printf("2nd wait error\n"); exit(2); } pr_exit(status); if((pid=fork()) < 0){ printf("3rd fork error\n"); exit(2); }else if(pid == 0) status /= 0; // generates SIGFPE, signal number is 8 if(wait(&status) != pid){ printf("3rd wait error\n"); exit(2); } pr_exit(status); exit(0); }
运行结果如下。
$ ./exitStatusDemo.out normal terminaltion, exit status = 7 abnormal termination, signal number = 6(core file generated) abnormal termination, signal number = 8(core file generated) $
如果一个进程有几个子进程,那么只要有一个子进程终止,wait 就返回。如果要等待一个指定的进程终止,waitpid 函数就派上用场了。对于 waitpid 函数中的 pid 参数的作用解释如下。
* pid == -1:等待任一子进程,此时等效于 wait。
* pid > 0:等待进程 ID 为 pid 的子进程。
* pid == 0:等待组 ID 等于调用进程组 ID 的任一子进程。
* pid < -1:等待组 ID 等于 pid 绝对值的任一子进程。
参数 options 可以进一步控制 waitpid 的操作。此参数可以为 0 或者是下表中各常量按位或运算的结果(FreeBSD 8.0 和 Solaris 10 支持另一个非标准的可选常量 WNOWAIT,它使系统将终止状态已由 waitpid 返回的进程保持在等待状态,这样它可被再次等待)。
如果一个进程 fork 了一个子进程,但不要它等待子进程终止,也不希望子进程处于僵死状态直到父进程终止,实现这一要求的诀窍就是调用 fork 两次,正如下列这个程序所示。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main(void){ pid_t pid; if((pid=fork()) < 0){ printf("1st fork error\n"); exit(2); }else if(pid == 0){ // first child if((pid=fork()) < 0){ printf("2nd fork error\n"); exit(2); }else if(pid > 0){ exit(0); // parent from second fork == first child } /* We're the second child; our parent becomes init as soon as * our real parent calls exit() in the statement above. Here's * where we'd continue executing, knowing that when we're * done, init will reap our status. */ sleep(2); printf("second child, parent pid=%ld\n", (long)getppid()); exit(0); } if(waitpid(pid, NULL, 0) != pid){ // wait for first child printf("waitpid error\n"); } /* We're the parent(the original process); we continue executing, * knowing that we're not the parent of the second child. */ exit(0); }
执行结果:
$ ./fork2timesDemo.out $ second child, parent pid = 1
注意,这里当原先的进程(即 exec 本程序的进程)终止时,shell 打印其提示符,因为这在第二个子进程打印其父进程 ID 之前发生。
另外,Single UNIX Specification 包含了另一个取得进程终止状态的函数----waitid,此函数类似于 waitpid,但提供了更多的灵活性。
#include <sys/wait.h> int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); /* 返回值:若成功,返回 0;否则,返回 -1 */
waitid 也允许一个进程指定要等待的子进程,但它使用两个单独的参数表示要等待的进程所属的类型,而不是将此与进程 ID 或进程组 ID 组合成一个参数。id 参数的作用与 idtype 的值相关。该函数支持下表中的这几个 idtype 类型。
options 参数是下表中各标志的按位或运算,这些标志指示调用者关注哪些状态变化。
注意,WCONTINUED、WEXITED 和 WSTOPPED 这 3 个常量之一必须指定。
infop 参数是指向 siginfo 结构的指针,该结构包含了造成子进程状态改变有关信号的详细信息。
大多数 UNIX 系统实现还提供了 wait3 和 wait4 函数,它们提供的功能比上面几个 wait 函数提供的要多一个,这与附加参数有关,该参数允许内核返回由终止进程及其所有子进程使用的资源情况。资源统计信息(不同于资源限制)包括用户 CPU 时间总量、系统 CPU 时间总量、缺页次数、接收到信号的次数等,有关细节可查阅 getrusage(2) 手册页。
#include <sys/types.h> #include <sys/wait.h> #include <sys/time.h> #include <sys/resource.h> pid_t wait3(int *statloc, int options, struct rusage *rusage); pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage); /* 两个函数返回值:若成功,返回进程 ID;否则,返回 -1 */
发表评论
-
打开伪终端设备
2018-07-09 20:50 1249在伪终端概述一节中已对 PTY进行了初步的介绍。尽管 ... -
伪终端概述
2018-06-02 11:05 1542伪终端就是指,一个应用程序看上去像一个终端,但事实上它 ... -
终端窗口大小和 termcap
2018-05-29 22:39 795多数 UNIX 系统都提供了一种跟踪当前终端窗口大小的 ... -
终端规范模式和非规范模式
2018-05-29 00:25 944终端规范模式很简单:发一个读请求,当一行已经输入后,终 ... -
终端标识
2018-05-23 11:18 567尽管控制终端的名字在多数 UNIX 系统上都是 /de ... -
波特率和行控制函数
2018-05-22 07:53 937虽然大多数终端设 ... -
终端属性和选项标志
2018-05-20 07:40 707tcgetattr 和 tcsetattr ... -
终端特殊输入字符
2018-05-17 06:33 810终端支持下表所示的特殊输入字符。 为了更改 ... -
终端 I/O 综述
2018-05-10 07:56 434终端设备可认为是由内核中的终端驱动程序控制的。每个终端 ... -
POSIX 信号量
2018-05-09 00:03 577在XSI IPC通信之信 ... -
XSI IPC 通信之共享存储
2018-04-25 07:18 945在XSI IPC通信之消息队列和XSI IPC通信之信 ... -
XSI IPC通信之信号量
2018-04-17 23:38 614在XSI IPC通信之消 ... -
XSI IPC通信之消息队列
2018-04-15 10:54 492消息队列是消息的链接表,存储在内核中,由消息队列标识符 ... -
XSI IPC 相似特征介绍
2018-02-08 23:48 482有 3 种称作 XSI IPC ... -
IPC 通信之 FIFO
2018-02-06 22:55 413FIFO 也被称为命名管道,未命名的管道只能在两个相关 ... -
IPC 通信之管道
2018-01-30 22:22 384管道是 UNIX 系统 IPC 的最古老但也是最常用的 ... -
readv/writev 函数及存储映射 I/O
2018-01-19 00:57 879readv 和 writev 函数可用于在一次函数调用 ... -
POSIX 异步 I/O
2018-01-16 21:33 453POSIX 异步 I/O 接口为对不同类型的文件进行异 ... -
fcntl 记录锁
2018-01-06 23:48 596记录锁的功能是:当有进程正在读或修改文件的某个部分时, ... -
守护进程惯例
2018-01-06 23:52 434UNIX 系统中,守护进程遵循下列通用惯例。 ...
相关推荐
`waitpid`函数在`<sys/wait.h>`头文件中定义,其基本原型为: ```c pid_t waitpid(pid_t pid, int *status, int options); ``` - `pid_t pid`: 表示要等待的特定子进程ID。如果设置为-1,表示等待任何子进程。 - `...
Linux 操作系统中,僵死进程(Zombie Process)是一种特殊的进程状态,它是指一个进程已经终止,但是其父进程没有通过wait或waitpid函数来回收它的状态信息,而使得进程所占用的资源无法释放,导致系统资源的浪费。...
Linux中的`wait`和`waitpid`是两个用于管理子进程状态的重要系统调用,它们在多进程编程中扮演着关键角色。本文将对这两个函数进行深入分析。 ### `wait`函数 `wait`函数的基本原型如下: ```c pid_t wait(int *...
- **wait和waitpid函数**:这两个函数用于等待子进程结束,并获取其退出状态,从而避免僵尸进程的产生。`wait()`会等待所有子进程,而`waitpid()`可以指定等待特定的子进程。 - **处理僵尸进程的方法**:通过调用`...
C语言wait()函数:结束(中断)进程函数(常用) 头文件: #include <sys> #include 定义函数: pid_t wait (int * status); 函数说明:wait()会暂时停止目前进程的执行, 直到有信号来到或子进程结束. 如果在调用...
8.6 wait和waitpid函数 8.7 waitid函数 8.8 wait3和wait4函数 8.9 竞争条件 8.10 exec函数 8.11 更改用户ID和组ID 8.12 解释器文件 8.13 system函数 8.14 进程会计 8.15 用户标识 ...
它介绍了如何创建和管理进程,如何利用fork和exec函数家族来启动新的进程,以及如何通过wait和waitpid函数来等待子进程的结束。对于线程管理,书中有详尽的多线程编程指南,包括线程的创建、同步与通信,如使用互斥...
8.6 wait和waitpid函数 148 8.7 wait3和wait4函数 152 8.8 竞态条件 153 8.9 exec函数 156 8.10 更改用户ID和组ID 160 8.11 解释器文件 164 8.12 system函数 167 8.13 进程会计 171 8.14 用户标识 175 8.15 进程时间...
8.6 wait和waitpid函数 148 8.7 wait3和wait4函数 152 8.8 竞态条件 153 8.9 exec函数 156 8.10 更改用户ID和组ID 160 8.10.1 setreuid 和setregid函数 162 8.10.2 seteuid和 setegid函数 163 8.10.3 组ID 163 8.11 ...
8.6 wait和waitpid函数 179 8.7 waitid函数 183 8.8 wait3和wait4函数 184 8.9 竞争条件 185 8.10 exec函数 188 8.11 更改用户ID和组ID 192 8.12 解释器文件 196 8.13 system函数 200 8.14 进程...
8.6 wait和waitpid函数 148 8.7 wait3和wait4函数 152 8.8 竞态条件 153 8.9 exec函数 156 8.10 更改用户ID和组ID 160 8.10.1 setreuid 和setregid函数 162 8.10.2 seteuid和 setegid函数 163 8.10.3 组ID 163 8.11 ...
164 7.12 小结 168 习题 168 第8章 进程控制 171 8.1 引言 171 8.2 进程标识符 171 8.3 fork函数 172 8.4 vfork函数 176 8.5 exit函数 178 8.6 wait和waitpid函数 179 8.7 waitid函数 183 8.8 ...
8.6 wait和waitpid函数 148 8.7 wait3和wait4函数 152 8.8 竞态条件 153 8.9 exec函数 156 8.10 更改用户ID和组ID 160 8.10.1 setreuid 和setregid函数 162 8.10.2 seteuid和 setegid函数 163 8.10.3 组ID 163 8.11 ...
8.6 wait和waitpid函数 148 8.7 wait3和wait4函数 152 8.8 竞态条件 153 8.9 exec函数 156 8.10 更改用户ID和组ID 160 8.10.1 setreuid 和setregid函数 162 8.10.2 seteuid和 setegid函数 163 8.10.3 组ID ...