wait和waitpid
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int * status);
//成功返回被等待进程pid,失败返回-1
//参数获取子进程退出状态,不关心可设为NULL
pid_t waitpid(pid_t pid, int *status, int options);
/*
**正常返回收集到的子进程id
**若设置了WNOHANG选项,调用中发现没有已退出的子进程可收集,返回0
**出错返回-1
**pid:"=-1",等待任一个子进程,与wait等效;">0"等待id为pid的子进程
**status:"WIFEXITED(status)",查看进程是否正常退出;"WEXITSTATUS(status)",查看进程退出码
**options:"WNOHANG",若指定子进程未结束,返回0,否则返回子进程id
*/
1、获取子进程status
- wait和waitpid都有status参数,是一个输出型参数
- 传值NULL表示不关心子进程退出状态信息
- 操作系统会根据该参数将子进程退出信息反馈给父进程
研究status低16比特位:
- 正常终止:8位退出状态 + 8位零
- 被信号所杀:8位未用 + core dump标志 + 终止信号
#include<sys/wait.h>
#include<unistd.h>
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
int main()
{
pid_t pid = fork();
if(pid == -1)
{
perror("error");
exit(1);
}
if(pid == 0)
{
sleep(20);
exit(8);
}
else
{
int status;
int ret = wait(&status);
if(ret > 0 && (status & 0x7F) == 0)
{
//正常退出
cout<<"child exit code:"<<((status>>8) & (0xFF))<<endl;
}
else if(ret > 0)
{
//异常退出
cout<<"sig code:"<<((status) & (0x7F))<<endl;
}
}
return 0;
}
第一次运行什么都不做,程序正常退出,返回退出状态码;
第二次运行时,打开另一个终端,找到子进程id,kill掉,程序异常退出,返回终止信号码;
进程的阻塞等待方式
#include<sys/wait.h>
#include<sys/types.h>
#include<unistd.h>
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
int main()
{
pid_t pid = fork();
if(pid == -1)
{
perror("error");
exit(1);
}
if(pid == 0)
{
cout<<"child pid:"<<getpid()<<endl;
sleep(5);
exit(257);
}
else
{
int status = 0;
pid_t ret = waitpid(-1, &status, 0);
if(WIFEXITED(status) && (ret == pid))
{
cout<<"child exit code:"<<WEXITSTATUS(status)<<endl;
}
else
{
cout<<"failed"<<endl;
exit(1);
}
}
return 0;
}
2、进程程序替换
替换原理
- 用fork创建子进程后执行的是和父进程相同的程序,有可能执行不同的代码分支
- 子进程往往要调用一种exec函数以执行另一个程序
- 当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行
- 调用exec并不创建新进程,所以调用exec前后该进程的id并未改变
替换函数
只有execve是真正的系统调用,上面几个最终调用execve
函数解释
- 调用成功则加载新程序开始执行,不再返回
- 调用出错返回-1
命名解释
- l(list):参数采用列表
- v(vector):参数采用数组
- p(path):自动搜索环境变量PATH
- e(env):自己维护环境变量
举例
#include<unistd.h>
int main()
{
char *const argv[] = {"ps", "-ef", NULL};
char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};
execl("/bin/ps", "ps", "-ef", NULL);
execlp("ps", "ps", "-ef", NULL);
execle("ps", "ps", "-ef", NULL, envp);
execv("/bin/ps", argv);
execvp("ps", argv);
execve("/bin/ps", argv, envp);
return 0;
}
调用exec
执行ls -l
指令
#include<unistd.h>
int main()
{
char *const argv[] = {"ls","-l",NULL};
char *const envp[] = {"PATH=/bin:/usr/bin","TERM=console",NULL};
execve("/bin/ls",argv,envp);
return 0;
}