[学习笔记]父进程wait和waitpid
1、wait和waitpid出现的原因 |
SIGCHLD q 当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止) q 子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程,它只保留最小的一些内核数据结构,以便父进程查询子进程的退出状态。 父进程查询子进程的退出状态可以用wait/waitpid函数 |
2、wait和waitpid函数用法 |
Wait q 头文件<sys/types.h>和<sys/wait.h> q 函数功能:当我们用fork启动一个进程时,子进程就有了自己的生命,并将独立地运行。有时,我们需要知道某个子进程是否已经结束了,我们可以通过wait安排父进程在子进程结束之后。 q 函数原型 q pid_t wait(int *status) q 函数参数 q status:该参数可以获得你等待子进程的信息 q 返回值: q 成功等待子进程函数返回,返回值是等待子进程的ID q wait系统调用会使父进程暂停执行,直到它的一个子进程结束为止。 q 返回的是子进程的PID,它通常是结束的子进程 q 状态信息允许父进程判定子进程的退出状态,即从子进程的main函数返回的值或子进程中exit语句的退出码。 q 如果status不是一个空指针,状态信息将被写入它指向的位置 |
Wait获取status后检测处理 宏定义 描述 WIFEXITED(status) 如果子进程正常结束,返回一个非零值 WEXITSTATUS(status) 如果WIFEXITED非零,返回子进程退出码 WIFSIGNALED(status) 子进程因为捕获信号而终止,返回非零值 WTERMSIG(status) 如果WIFSIGNALED非零,返回信号代码 WIFSTOPPED(status) 如果子进程被暂停,返回一个非零值 WSTOPSIG(status) 如果WIFSTOPPED非零,返回一个信号代码
|
Waitpid q函数功能:用来等待某个特定进程的结束 q函数原型: pid_t waitpid(pid_t pid, int *status,int options) q参数: q status:如果不是空,会把状态信息写到它指向的位置 qoptions:允许改变waitpid的行为,最有用的一个选项是WNOHANG,它的作用是防止waitpid把调用者的执行挂起 q 返回值:如果成功返回等待子进程的ID,失败返回-1
|
对于waitpid的p I d参数的解释与其值有关: q pid == -1 等待任一子进程。于是在这一功能方面waitpid与wait等效。 q pid > 0 等待其进程I D与p I d相等的子进程。 q pid == 0 等待其组I D等于调用进程的组I D的任一子进程。换句话说是与调用者进程同在一个组的进程。 q pid < -1 等待其组I D等于p I d的绝对值的任一子进程。
|
3、wait pk waitpid |
Wait和waitpid区别和联系 q 在一个子进程终止前, wait 使其调用者阻塞,而waitpid 有一选择项,可使调用者不阻塞。 q waitpid并不等待第一个终止的子进程—它有若干个选择项,可以控制它所等待的特定进程。 q 实际上wait函数是waitpid函数的一个特例。
|
僵尸进程 q 当一个子进程结束运行时,它与其父进程之间的关联还会保持到父进程也正常地结束运行或者父进程调用了wait才告终止。 进程表中代表子进程的数据项是不会立刻释放的,虽然不再活跃了,可子进程还停留在系统里,因为它的退出码还需要保存起来以备父进程中后续的wait调用使用。它将称为一个“僵进程” |
如何避免僵尸进程 |
q 调用wait或者waitpid函数查询子进程退出状态,此方法父进程会被挂起。 q 如果不想让父进程挂起,可以在父进程中加入一条语句:signal(SIGCHLD,SIG_IGN);表示父进程忽略SIGCHLD信号,该信号是子进程退出的时候向父进程发送的。 |
#include <sys/types.h> #include <unistd.h> #include "errno.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include <sys/types.h> #include <sys/wait.h> void LoopFunc(int num) { printf("LoopFunc() %d....\n", num); } int main(void ) { int i , j = 0; printf("hello...\n"); int procNum = 0; int loopNum = 0; printf("\n请输入要运行的进程数"); scanf("%d", &procNum); printf("\n请输入每个进程运行圈数"); scanf("%d", &loopNum); pid_t pid; printf("befor fork pid:%d\n", getpid()); //fork 子进程 for (i=0; i<procNum; i++) { pid = fork(); if (pid == -1) { //On failure, a -1 will be retur //errno perror("fork err"); return 0; } if (pid == 0) { for (j=0; j<loopNum; j++) { LoopFunc(j); } exit(0); //让子进程跑圈 子进程不参与下一次的fork } if (pid > 0) //大于0是父进程 { ; } } //退出 printf("after fork \n"); int mypid ; while( (mypid = waitpid(-1, NULL, WNOHANG)) > 0) { printf("孩子死掉:%d\n ", mypid); }return 0; }