目录

1.进程等待

1.1进程等待必要性

1.2进程等待的方法

1.3获取子进程status

​2.程序替换

2.1替换原理

2.2替换函数

2.3execl使用实例:

2.4 minishell实现


1.进程等待

1.1进程等待必要性

·子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏。

·父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对, 或者是否正常退出。

·父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息

1.2进程等待的方法

wait方法 

#include<sys/types.h>

#include<sys/wait.h>

pid_t wait(int* status);

wait是一个阻塞接口,功能是等待当前调用者的任意一个子进程退出(如果已经有退出的直接处理),获取返回值,释放资源

返回值:成功返回被等待进程pid,失败返回-1

status参数:是一个int空间的地址,用于向指定空间中存放子进程的退出返回值

waitpid方法 

pid_t waitpid(pid_t pid,int* status,int options);

waitpid接口既可以等待任意一个子进程退出,也可以等待指定的子进程退出

pid参数:>0则表示等待指定pid的子进程退出;

-1表示等待任意一个子进程的退出

waitpid接口既可以阻塞等待,也可以使用非阻塞等待

options参数:0-表示默认阻塞等待;

                      WNOHANG-设置为非阻塞(当前没有子进程退出则会返回0)

返回值:成功则返回处理的退出子进程的pid,若没有子进程退出则返回0;出错则返回-1

阻塞接口:

为了完成一个功能发起了一个调用,但是这个调用完成条件不具备,则接口一直等待不返回。

操作流程简单,但是对资源利用率较低。

非阻塞接口:

为了完成一个功能发起了一个调用,但是这个调用完成条件不具备,则立即报错返回。

操作流程稍微复杂一些(通常需要循环操作),但是对资源的利用率较高。

1.3获取子进程status

wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。

如果传递NULL,表示不关心子进程的退出状态信息。

否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。

status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位):

通过wait获取的返回值,有多个信息,其中进程的退出码只是其中一部分,并且只用了1个字节保存(如果exit给的退出码过大,就会截断)

coredump翻译过来就是核心转储,当程序异常退出的时候,保存程序运行信息,便于能够事后调试,默认处于关闭状态(隐私&安全,占据磁盘空间)

异常信号值--作用就是保存退出异常退出原因,为0则表示程序是正常退出,非0则表示异常退出

因此 要获取一个进程的退出码,首先得确定这个进程是否是正常退出,如果是,才有意义

代码中关心的问题:

如何判断进程是否是正常退出:取出status中的低7位--status & 0x7f

        如何从status中取出退出码:取出status中的低16位中的高8位--(status>>8) & 0xff

获取status实例:

 #include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/wait.h>//wait&waitpidint main()
{pid_t cpid=fork();if(cpid < 0){perror("fork error");}else if(cpid==0){printf("i am child process!\n");sleep(5);exit(99);}int status,ret;while((ret=waitpid(-1,&status,WNOHANG))==0){printf("现在子进程还没退出...\n");sleep(2);}                                                                                                                                                                                    if(ret<0){perror("fork error");return -1;}if((status & 0x7f)== 0){printf("%d 子进程退出了! 返回值是:%d\n",ret,(status>>8)&0xff);}else{printf("子进程是异常退出的!\n");}sleep(10000000);return 0;}

 异常退出实例:

2.程序替换

2.1替换原理

用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数 以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动 例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

其实就是加载一个新的程序到内存中,将指定进程的pcb页表映射信息进行修改,让其调度管理新的程序运行。

2.2替换函数

其实有六种以exec开头的函数,统称exec函数:

#include  <unistd.h>

int execl(const char *path, const char *arg, ...);

int execlp(const char *file, const char *arg, ...);   //int execlp("ls","ls","-l",NULL)

int execle(const char *path, const char *arg, ...,char *const env[]);//int execle("/bin/ls","ls","-l",NULL,env);

int execv(const char *path, char *const argv[]);//

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

int execve(const char *path, char *const argv[], char *const env[]);

返回值:

这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。

如果调用出错则返回-1

所以exec函数只有出错的返回值而没有成功的返回值。

2.3execl使用实例:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main(int argc,char *argv[],char *env[]){printf("本来运行程序的起始~\n");execlp("ls","ps",NULL);                                                            printf("本来程序结束\n");}

原程序在运行到execlp函数时发生了替换,执行了ls程序,原程序不再执行。

2.4 minishell实现

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>int main(){while(1){printf("【user@host ~】$ ");fflush(stdout);//刷新标准输出缓冲区char cmd[1024]={0};fgets(cmd,1023,stdin);//获取键盘输入的一行数据cmd[strlen(cmd)-1]='\0';//取出行尾的换行字符int argc=0;                  char *argv[32]={NULL};                    char *ptr=cmd;argv[argc++]=strtok(cmd," ");//字符串分割函数,以指定字符作为间隔符对字符串进行分割while((argv[argc]=strtok(NULL," "))!=NULL){                          argc++;}                if(strcmp(argv[0],"cd")==0){chdir(argv[1]); //改变工作路径, 工作路径改到哪里,哪里就是当前所在目录continue;    }pid_t child_pid=fork();if(child_pid<0){perror("fork error");                                                                                                                                                          continue;              }else if(child_pid==0){//子进程进行程序替换,执行指令程序execvp(argv[0],argv);perror("execvp error");exit(-1);}wait(NULL);//每一个子进程运行完毕后,才能开始捕捉下一个输入进行操作}return 0;}

进程控制——进程等待,程序替换相关推荐

  1. 进程控制(进程创建与终止 | 进程等待 | 程序替换)

    文章目录 一.进程创建 1. fork函数 2. fork创建进程 3. 写时拷贝 二.进程终止 1. 进程退出有三种情况 2. 常见进程终止方法 三.进程等待 背景(必要性) 1. 进程等待的方法 ...

  2. Linux——详解进程控制之等待

    进程等待是进程控制中非常重要的一环,这关系着多进程之间的联动. 目录 一.概念 二.wait 三.waitpid (一).  pid_t pid (二).  int* status ※ ①退出码 ②退 ...

  3. 【Linux】进程控制 —— 进程创建/终止/等待

    目录 一.进程创建 1.fork创建子进程,操作系统做了什么? 2.fork的用法以及失败的原因 二.进程终止 1.三种退出情况 2.main函数为什么一般情况下都要return 0 3.进程的退出码 ...

  4. Linux - 进程控制(进程替换)

    0.引入 创建子进程的目的是什么? 就是为了让子进程帮我执行特定的任务 让子进程执行父进程的一部分代码 如果子进程想执行一个全新的程序代码呢? 那么就要使用进程的程序替换 为什么要有程序替换? 也就是 ...

  5. 操作系统学习笔记02【进程控制——进程互斥的硬件实现方法】【自用】

    1.进程控制 什么是进程控制? 如何实现进程控制: 为了避免把某一进程pbc从一个队列转移到另一个队列,但是并没有把pbc内的状态标志改为新的对应状态,从而导致pcb的状态标志与实际所处队列不一样这一 ...

  6. 【Linux】Linux进程控制 --- 进程创建、终止、等待、替换、shell派生子进程的理解…

    柴犬: 你好啊,屏幕前的大帅哥or大美女,和我一起享受美好的今天叭

  7. 【Linux】进程控制 — 进程终止 + 进程等待

    文章目录

  8. Linux 进程控制 :进程创建,进程终止,进程等待,程序替换

    进程创建 进程终止 进程等待 程序替换 进程创建 fork函数 创建一个子进程,父子进程代码共享,数据独有 #include <unistd.h> pid_t fork(void); 返回 ...

  9. 进程程序替换((>_<)子进程跑了),模拟编写一个入门shell

    目录 进程程序替换 1.进程替换的原理 2.怎么来另起炉灶执行另一个程序 ①execl ②execv ③execlp ④execvp​编辑 ⑤execle ⑥execvpe 和 execve 3.执行 ...

最新文章

  1. 15 - 使用 Fabric 自动化部署
  2. php disable classes,PHP安全配置基础教程(3)
  3. vue-router之路由属性配置说明(十)
  4. The Design and Implementation of Open vSwitch
  5. 设备管理器中的计算机有什么用,为什么计算机设备管理器中有两个图形卡?
  6. 微服务 第六章 springboot 通过Spring-data-jpa 配置Oracle数据源(简单步骤)
  7. cv1159 最大全0子矩阵(极大子矩阵)
  8. 3.spring boot Controller获取请求参数的值
  9. linux中timer的作用,linux - linux / timer.h setup_timer()到期功能不起作用? - 堆栈内存溢出...
  10. 通过反射获取私有方法
  11. 关于用Linux桌面版当工作系统这件事
  12. 服务器系统无法共享打印机驱动程序,windows-server-2003 – windows服务器共享打印机,为什么本地机器需要驱动程序?...
  13. 评分卡模型开发(四)--定量指标筛选
  14. pdf怎么打开上次看到的地方_ppt如何转pdf?俩种方法轻松搞定
  15. FPGA学习 Vivado使用篇
  16. cesium obj格式转换为gltf、glb
  17. 欧洲肿瘤生物学博士后申请经历
  18. 宠物小精灵之收服(二维01背包)
  19. Golang工具集-String工具,时间工具,http工具等
  20. mybatis的几种锁

热门文章

  1. 激活层是每一层都有吗_每一个成功男人的背后,都有一个特别的妻子吗?
  2. MongoDB和Node.js的Mongoose简介
  3. C语言rand()函数解析
  4. 追逐——从《棋魂》谈起……
  5. Module build failed: BrowserslistError:
  6. mysql存储过程concat_mysql 存储过程 CONCAT 字符串拼接
  7. 【UE4 第一人称射击游戏】47-修改AI为僵尸样貌
  8. PoseiSwap IDO在Bounce上启动在即,如何参与?
  9. MATLAB--数字图像处理 图像的灰度变换与直方图修正
  10. Excel VBA小程序 -批量合并和撤销合并单元格