- 代码运行完毕,结果正确
- 代码运行完毕,结果不正确
- 代码异常终止 CREASH
类似错误码,不同的值代表不用意义

父进程等待子进程是不做任何事情,为阻塞等待
父进程等待子进程时,通过重复wait轮询,不断获取子进程的执行状态
OS中,进程因为等待某些资源,而卡住的情形即阻塞等待
而WNOHANG即非阻塞等待
pid_t waitpid(pid_t pid, int *status, int options);
返回值
- 进程退出,返回id,但是不能保证进程是否正常退出,还是CRESASH
- 进程没有退出,返回0,----与非阻塞等待有关系
- 等待进程失败,返回-1
pid_t pid
pid=-1,等待任意一个子进程
pid>0,等待与pid想等的id进程
int *status
status是一个输出型参数,与子进程退出信息强相关
因为status指向对象是一个int类型,即有32个比特位,因此通过低16位来反映进程的退出信息,通过第0~6位反映信号,通过 第8~15位反映退出码
宏:WEXITSTATUS获得退出码,但是退出的3种情形都会返回id,防止退出码失去意义,可以通过 宏:WIFEXITED来判断是否是正常退出,还是异常退出
>WIFEXITED:正常退出返回 true,否则返回false > >WEXITSTATUS:若WIFEXITED为真即正常退出,返回退出码
- 1
- 2
- 3
```c++ int status=0; 37 pid_t ret= waitpid(-1,&status,0); 38 if(ret>0) 39 { 40 printf("ret =%d\n",ret); 41 //正常运行, 42 if(WIFEXITED(status)) 43 { 44 45 printf("exit code :%d\n",WEXITSTATUS(status)); 46 } 47 else{ 48 printf("error get a singal :%d\n",status&0x7f); 49 50 } 51 } 52 // printf("father wait: %d,success. status exit code:%d,status exit signal %d\n",ret,(status>>8)&0x ff,status&0x7f); ```
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
options
options=0:默认是阻塞等待
options=WNOHANG:非阻塞等待
int main()
{
pid_t id =fork();
if(id==0)
{
int cnt =10;
while(cnt)
{
printf("child[%d]is running;cnt = %d\n",getpid(),cnt);
--cnt;
sleep(1);
}
exit(EXIT_SUCCESS);
}
// sleep(10);
printf("father begin\n");
int status=0;
while(1)
{
pid_t ret= waitpid(id,&status,WNOHANG);
if(ret>0) //子进程退出,等待成功
{
//正常运行,
if(WIFEXITED(status))
{
printf("exit code :%d\n",WEXITSTATUS(status));
}
else//异常退出
{
printf("error get a singal :%d\n",status&0x7f);
}
break;
}else if(ret==0)//子进程未退出
{
printf("do father thing \n ");
}
else
{
printf(" wait failure\n");
break;
}
sleep(1);
}
// printf("father wait: %d,success. status exit code:%d,status exit signal %d\n",ret,(status>>8)&0xff,status&0x7f);
printf("father end\n");

替换函数依据不同需求,有多重形式,但是功能是一样的
- l(list) : 表示参数采用列表
- v(vector) : 参数用数组
- p(path) : 有p自动搜索环境变量PATH
- e(env) : 表示自己维护环境变量
int execl(const char *path, const char *arg, ...);

返回值
因为新的程序会替换原先子进程代码,所以成功时检测返回值是没有意义的,如果替换失败,返回-1,继续执行原先代码
path
可执行文件的路径+ 文件名
“./myexe”
arg
- 类似命令行参数,是一个argv指针数组,但是用列表的形式传参,内部会封装对参数的处理细节。
- 必须要以NULL结尾
execl(…“ls”,“-al”,NULL)
int execv(const char *path, char *const argv[]);

返回值
同execl
path
同execl
argv
- 传入一个指针数组,数组内容是命令行参数
int execlp(const char *file, const char *arg, ...);
同execl类似,唯一的区别是,因为环境变量的存在,进程会依据PATH自己寻找到相应的文件

int execvp(const char *file, char *const argv[]);

类似execv,唯一的区别是,因为环境变量的存在,进程会依据PATH自己寻找到相应的文件
int execle(const char *path, const char *arg, ...,char *const envp[]);

这个函数是系统调用函数,其它函数都是通过execve封装的库函数

int execve(const char *path, char *const argv[], char *const envp[])
直接打开是:建立一个新的进程
程序替换是:覆盖子进程原有的代码和数据
子进程执行的新程序一般是第三方指令,即bin目录下的指令
而对于内键的指令如:cd,pwd指令,需要父进程自己执行

#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAX 100
int main()
{
string s;
while(1)
{
printf("[New_Young@VM-12-17-centos minshel$] ");
s.clear();
//获取一行字符
getline(cin,s);
//分割字符串
const char * sep=" ";
// s的c_str()函数返回的是一个常量指针,strok需要一个指针a
//
char *command= new char[s.size()+1];
strcpy(command,s.c_str());
char *argv[MAX]={0};
argv[0]= strtok(command,sep);
int i=1;
while( argv[i]=strtok(NULL,sep) )
{
++i;
}
printf("begin:\n");
// 检测是否为内键指令
if(strcmp(argv[0],"cd")==0)
{
if(argv[1]!=NULL)chdir(argv[1]);
continue;
}
if(fork()==0)
{
execvp(argv[0],argv);
printf(" failure\n");
exit(1);
}
int ret= waitpid(-1,&status,0);
if(ret>0)
{
if( WIFEXITED(status))
{
printf("exit code: %d \n",WEXITSTATUS(status));
}else{
printf("exit signal: %d\n",status&0x7f);
}
}else{
printf(" wait failure\n");
}
printf("end\n");
return 0;
}