`

wait 和 waitpid 函数

阅读更多
    当一个进程正常终止或异常终止时,内核就会向其父进程发送 SIGCHLD 信号,父进程对这种信号的默认动作是忽略它。可以使用 wait 和 waitpid 函数来获取子进程的终止状态。
#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 */

  • 大小: 33.5 KB
  • 大小: 16.8 KB
  • 大小: 7.7 KB
  • 大小: 12.2 KB
分享到:
评论

相关推荐

    Linux进程控制编程-waitpid函数实例.pdf

    `waitpid`函数在`&lt;sys/wait.h&gt;`头文件中定义,其基本原型为: ```c pid_t waitpid(pid_t pid, int *status, int options); ``` - `pid_t pid`: 表示要等待的特定子进程ID。如果设置为-1,表示等待任何子进程。 - `...

    Linux僵死进程的产生与避免.pdf

    Linux 操作系统中,僵死进程(Zombie Process)是一种特殊的进程状态,它是指一个进程已经终止,但是其父进程没有通过wait或waitpid函数来回收它的状态信息,而使得进程所占用的资源无法释放,导致系统资源的浪费。...

    linuxwait与waitpid函数的深入分析[参考].pdf

    Linux中的`wait`和`waitpid`是两个用于管理子进程状态的重要系统调用,它们在多进程编程中扮演着关键角色。本文将对这两个函数进行深入分析。 ### `wait`函数 `wait`函数的基本原型如下: ```c pid_t wait(int *...

    Unix实验三.doc

    - **wait和waitpid函数**:这两个函数用于等待子进程结束,并获取其退出状态,从而避免僵尸进程的产生。`wait()`会等待所有子进程,而`waitpid()`可以指定等待特定的子进程。 - **处理僵尸进程的方法**:通过调用`...

    详解C语言中的wait()函数和waitpid()函数

    C语言wait()函数:结束(中断)进程函数(常用) 头文件: #include &lt;sys&gt; #include 定义函数: pid_t wait (int * status); 函数说明:wait()会暂时停止目前进程的执行, 直到有信号来到或子进程结束. 如果在调用...

    UNIX环境高级编程_第二版中文

    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 用户标识  ...

    UNIX环境高级编程

    它介绍了如何创建和管理进程,如何利用fork和exec函数家族来启动新的进程,以及如何通过wait和waitpid函数来等待子进程的结束。对于线程管理,书中有详尽的多线程编程指南,包括线程的创建、同步与通信,如使用互斥...

    UNIX环境高级编程 pdf格式

    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 进程时间...

    IT行业中必备技能之UNIX最佳学习资料

    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 ...

    UNIX环境高级编程(第二版中文)

    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 进程...

    UNIX环境高级编程和源代码

    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 ...

    unix环境编程电子书

    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 ...

    UNIX环境高级编程(PDF)

    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 ...

    Unix高级编程 pdf

    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 ...

Global site tag (gtag.js) - Google Analytics