(1)代码运行完毕,结果正确 退出码为0
(2)代码运行完毕,结果不正确 退出码非0
(3)代码异常终止 程序崩溃,退出码无意义
(1)正常终止:
(2)异常退出
#include
int main(){
printf("return 12\n");
return 12;
}
12是进程myproc的退出码(main函数的返回值 )
0是第一条echo的退出码
函数返回
参数:退出码
—————————————————————————————————————
父进程通过wait/waitpid等待子进程退出
为何让父进程等待?
1.通过获取子进程退出的信息,得到子进程执行的结果
2.可以保证:时序问题,子进程先于父进程退出
3.子进程退出,父进程不管不顾,可能进入僵尸状态,造成内存泄漏,需要通过父进程wait释放子进程占用的资源
通过stat_loc可以获取子进程退出的信息:
正常退出:第8-15位是子进程退出码,0-7位是退出信号(正常退出则为0)
被信号所杀:第0-6位是终止信号,第七位是core dump标志,不使用8-15
#include
#include //wait
#include // wait
#include // exit
#include // fork
//进程等待 wait
//子进程运行5s,父进程sleep10s,后5s子进程成为僵尸进程
//10s后父进程执行wait,回收子进程
int main(){
pid_t pid = fork();
if(pid == 0){
int cnt = 3;
while(cnt){
printf("child[%d] is running,cnt = %d\n",getpid(),cnt);
cnt--;
sleep(1);
}
// 浮点型错误,退出信号=8
//int a = 10;
//a/=0;
exit(11);
}
sleep(5);
//pid_t ret = wait(NULL);// 返回等待的子进程pid或-1,参数是退出码
//pid_t ret = waitpid(pid,NULL,0);// 返回值同上,pid设成1时等待任意一个子进程
int status = 0;
pid_t ret = waitpid(pid,&status,0);
if(ret>0){
// //printf("father wait:%d,status exit code:%d,status exit signal:%d\n",ret,(status>>8),status);
//printf("father wait:%d,status exit code:%d,status exit signal:%d\n",ret,(status>>8)&0xFF,status&0x7F);
if(WIFEXITED(status)){// 没有收到退出信号
// 正常结束的 获取对应退出码
printf("exit code:%d\n",WEXITSTATUS(status));
}else{
printf("error,get a signal\n");
}
}else{
printf("father failed\n");
}
return 0;
}
进程的等待方式:
(1)阻塞等待:
阻塞的本质是进程的PCB被放入等待队列,并将进程的状态修改为S状态
返回的本质是进程的PCB从等待队列拿到R队列,从而被CPU调度
waitpid(-1,&sataus,0);
(2)非阻塞等待
不断调度父进程
基于非阻塞的轮询等待方案
int ret = waitpid(-1,&sataus,WNOHANG);// WNOHANG:不阻塞模式
if(ret == 0){
//子进程没有退出,但是waitpid等待是成功的,需要父进程重复进行等待
}else if(ret > 0){
// 子进程退出了,waitpid也成功,获取了对应结果
}else{
//等待失败
}
进程不变,仅仅替换当前进程的 代码和数据
只要程序替换成功,就不会执行后续代码/ exec* 函数成功的时候不需要返回值检测,若exec*返回了就一定是调用失败了
让子进程执行一个“全新的程序”
execve:系统调用
int execl(const char *path, const char *arg, …);
int execlp(const char *file, const char *arg, …);
int execle(const char *path, const char *arg,…, char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
int execve(const char *filename, char *const argv[],char *const envp[]);
参数:const char *path:要执行的目标程序的全路径(所在路径/文件名)
const char *arg, …:要执行的目标程序,可变参数列表,以NULL作为传参的结束
execl("/usr/bin/ls","ls","-a","-l","-i",NULL);
char *argv[]={"ls","-a","-l","-i",NULL};
execv("/usr/bin/ls",argv);
execlp("ls","ls","-a","-l","-i",NULL);
execvp("ls",argv);
execl("./myexe","myexe",NULL);// 程序调换 调用我的另一个程序
char *env[] = {"MYENV=myenv","MYENV2=myenv",NULL};
execle("./myexe","myexe",NULL,env);
char *argv1[]={"myexe",NULL};
execve("./myexe",argv1,env);