函数wait
一个进程在终止时会关闭所有文件描述符,释放在用户空间释放的内存,但它的PCB还保留着,内核在其中保存一些信息:如果是正常终止时则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个,这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除这个进程,我们知道一个进程的退出状态可以在shell用特殊变量$?查看,因为shell是它的父进程,当它终止时shell调用wait或waitpid得到它的退出状态同时彻底清除这个进程。
1. 函数wait:一次只能回收一个子进程
pid_t wait(int *status); status传出参数
进程终止时,操作系统隐式回收机制会:1. 关闭所有的文件描述符 2. 释放用户空间分配的内存。内核PCB仍存在,其中保存该进程的退出状态。(正常终止--------退出值;异常终止-------终止信号)
可使用wait函数传出参数status来保存进程的退出状态,借助宏函数来进一步判断进程终止的具体原因,宏函数可分为三组:
- WIFEXITED(status):为非0,进程正常结束;WEXITSTATUS(status) :如上宏为真,使用此宏 获取进程退出状态(exit的参数)
- WIFSIGNALED(status):为非0,进程异常终止;WTERMSIG(status):如上宏为真,使用此宏 获取进程终止的那个信号编号
- WIFSTOPPED(status) :为非0,进程处于暂停状;WSTOPSIG(status):如上宏为真,使用此宏 获取进程暂停的那个信号编号
1. 测试代码
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <sys/wait.h> 5 6 int main(void) 7 { 8 pid_t pid, wpid; 9 pid = fork(); 10 11 if(pid == 0) 12 { 13 printf("---child, my parent = %d, going to sleep 10s ", getpid()); 14 sleep(10); 15 printf("---------child die -------------- "); 16 } 17 else if(pid > 0) 18 { 19 wpid = wait(NULL); 20 if(wpid == -1) 21 { 22 perror("wait error: "); 23 exit(1); 24 } 25 while(1) 26 { 27 printf("I am parent, pid = %d, my son = %d ", getpid(), pid); 28 sleep(1); 29 } 30 } 31 else 32 { 33 perror("fork"); 34 return 1; 35 } 36 return 0; 37 }
输出结果
1. 测试代码:
1 #include <stdio.h> 2 #include <unistd.h> 3 #include<sys/wait.h> 4 5 int main(int argc, const char* argv[]) 6 { 7 pid_t pid = fork(); 8 9 if (pid > 0) // 父进程 10 { 11 printf("parent process, pid = %d, ppid = %d ", getpid(), getppid()); 12 int status; 13 pid_t wpid = wait(&status); 14 15 if (WIFEXITED(status)) 16 printf("exit value: %d", WEXITSTATUS(status)); 17 if (WIFSIGNALED(status)) 18 printf("exit by signal: %d ", WTERMSIG(status)); //是否被信号杀死 19 20 printf(" die child pid = %d ", wpid); 21 } 22 else if(pid == 0) 23 { 24 sleep(1); 25 printf("child process, pid = %d, ppid = %d ", getpid(), getppid()); 26 } 27 for (int i = 0; i<5; ++i) 28 printf(" i = %d ", i); 29 return 9; 30 }
输出结果:
3. 测试代码:
1 #include <stdio.h> 2 #include <unistd.h> 3 #include<sys/wait.h> 4 5 int main(int argc, const char* argv[]) 6 { 7 pid_t pid = fork(); 8 9 if (pid > 0) //父进程 10 { 11 printf("parent process, pid = %d, ppid = %d ", getpid(), getppid()); 12 int status; 13 pid_t wpid = wait(&status); 14 15 if (WIFEXITED(status)) 16 printf("exit value: %d", WEXITSTATUS(status)); 17 if (WIFSIGNALED(status)) 18 printf("exit by signal: %d ", WTERMSIG(status)); //是否被信号杀 19 20 printf(" die child pid = %d ", wpid); 21 } 22 else if (pid == 0) 23 { 24 while(1) 25 { 26 sleep(1); 27 printf("child process, pid = %d, ppid = %d ", getpid(), getppid()); 28 } 29 } 30 for (int i = 0; i<5; ++i) 31 printf(" i = %d ", i); 32 return 9; 33 }
采取操作:
54270 54286 54286 54270 pts/18 54286 S+ 1000 0:00 ./test 54286 54287 54286 54270 pts/18 54286 S+ 1000 0:00 ./test 54256 54288 54288 54256 pts/4 54288 R+ 1000 0:00 ps ajx sunbin@sunbin:~$ kill -9 54287
输出结果:
函数waitpid
函数waitpid原型:作用同wait,但可指定pid进程清理,可以不阻塞( 一次只能回收一个子进程)
pid_t wait(pid_t pid, int *staloc, int options);
1. 参数pid:
- pid == -1:回收任一子进程
- pid > 0 :回收指定pid的进程
- pid == 0 :回收与父进程同一个进程组的任一个子进程
- pid < -1 :回收指定进程组内的任意子进程
2. 参数options:
- 设置为WNOHANG:函数不阻塞;
- 设置为0:函数阻塞。