Linux操作系统--进程等待
目录
1.进程等待的必要性
2进程等待的方法:
2.1wait方法
2.2waitpid方法
1.3获取子进程status
waitpid的使用
1.进程等待的必要性
之前在进程状态章节,我们讲过僵尸进程的危害。僵尸进程无法被杀死,需要通过进程等待来杀掉它,进而解决内存泄漏问题
我们通过进程进程等待,获得子进程的退出情况----父进程得知道自己布置给子进程的任务,它完成的怎么样了。
2进程等待的方法:
2.1wait方法
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int *status);
返回值:成功返回被等待进程pid,失败返回-1
参数:输出型参数,获取子进程退出状态,不关心则可以设置成为NULL
2.2waitpid方法
pid_t waitpid(pid_t pid, int *status, int options);
返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID;
如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
pid:
Pid = -1,等待任一个子进程,与wait等效Pid>0,等待其进程id与pid相等的子进程。
status:
WIFEXITED(status):若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)WEXITSTATUS(status):若WIFEXITED非零,提取子进程退出码。(查看进程退出码)
options:
WNOHANG:若pid指定的子进程没有结束,则waitpid()函数返回0,不及以等待。若正常结束,则返回该子进程的ID。
- 如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息
- 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞
- 如果不存在该子进程,则立即出错返回
1.3获取子进程status
- wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充
- 如果传递NULL,表示不关心子进程的退出状态信息
- 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程
- status不能简单的当作整型来看待,可以当作位图来看待
WIFEXITED
宏用于检测子进程是否正常退出
(status)
的最低八位 (&0xFF
) 被检查。- 如果这八个比特全为零,则说明子进程是由于调用
exit()
正常结束的。这意味着,如果子进程因接收到某种致命信号而被迫终止,那么这八个比特不会全部为零,从而使得
WIFEXITED
返回假值。
WEXITSTATUS
的工作原理一旦确认子进程确实正常退出(即
WIFEXITED(status)
返回真),就可以使用WEXITSTATUS
来获取实际的退出状态码。其典型定义如下:这里的关键操作有两点:
- 将整个
status
右移八位 (>> 8
) ,以便丢弃低位上的标志比特;- 接着再次与
0xFF
执行按位 AND 操作,确保只保留高位中的有效退出码4。因此,最终的结果是从原始
status
值中抽取出来的真正的退出状态码
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
int main()
{pid_t pid = fork();if(pid == -1){perror("fork");exit(1);}if(pid == 0){sleep(20);exit(10);}else{int st;int ret = wait(&st);//0x7F转成二进制1111 111,因为子进程正常退出st的0-7比特位都是0//我们&0x7F是为了验证子进程是否正常退出if(ret > 0 && (st & 0x7F)==0){printf("child exit code:%d\n",(st>>8)&0xFF);}else if(ret > 0){printf("sig code: %d\n",st&0x7f);}}return 0;
}
如果直接杀掉进程:
waitpid的使用
进程阻塞等待方式:
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>int main()
{pid_t pid = fork();if(pid < 0){perror("fork");exit(1);}else if(pid == 0){printf("child is run, pid is : %d\n",getpid());sleep(5);exit(257);}else{int status = 0;pid_t ret = waitpid(-1,&status,0);printf("this is test for wait\n");if(WIFEXITED(status) && ret == pid)printf("wait child 5s success, child return code is :%d\n",WEXITSTATUS(status));else{printf("wait child failed,return\n");return 1;}}return 0;
}
进程的非阻塞等待方式:
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>int main()
{pid_t pid = fork();if(pid < 0){perror("fork");exit(1);}else if(pid == 0){printf("child is run, pid is : %d\n",getpid());sleep(5);exit(1);}else{int status = 0;pid_t ret = 0;do{ret = waitpid(-1,&status,WNOHANG);if(ret == 0)printf("child is running\n");sleep(1);} while(ret == 0);if(WIFEXITED(status) && ret == pid)printf("wait child 5s success, child return code is :%d\n",WEXITSTATUS(status));else{printf("wait child failed,return\n");return 1;}}return 0;
}