进程控制

进程创建:

fork、vfork底层都是调用clone

fork():

1.复制:分配新的内存块和内核数据结构给子进程 ,将父进程部分数据结构内容拷贝至子进程 ,添加子进程到系统进程列表当中,fork返回,开始调度器调度

2.返回值:子进程返回0, 父进程返回的是子进程的pid,出错返回-1

vfork:共用虚拟地址,子进程先运行,直到子进程退出后或者子进程程序替换运行另一端程序后才会调用父进程

 

进程终止:

终止场景:正常终止,符合预期;正常终止,结果不符合预期;异常终止

正常退出的情况:

1.main函数 return

2.exit(库函数) 做了一系列收尾操作后才释放资源

3._exit(系统调用) 直接释放资源退出进程

为了保证数据的完整性,最好用exit函数进行退出,例如

int main(){
    printf("Using exit...\n");
    printf("this is the content in buffer");
    exit(0);
}

printf()函数使用的是缓冲I/O方式,该函数在遇到"\n"换行符时自动从缓冲区中将记录读出,exit()函数在程序终止前冲刷了缓冲区,所以即使printf中没有换行符,也将内容打印了出来

int main(){
    printf("Using exit...\n");
    printf("this is the content in buffer");
    _exit(0);
}

而_exit()函数没有冲刷缓冲区这一操作,直接使进程退出,因此printf中的"this is the content in buffer"就不会被打印出来

异常退出:

ctrl + c,信号终止

 

进程等待:等待子进程退出,避免产生僵尸进程

为什么需要进程等待:当一个进程创建了新的进程时,父进程(原进程)往往需要读取子进程(新进程)的运行结果。如果子进程先于父进程退出,而父进程不能及时读取子进程的退出状态的话,子进程便会一直存在,此时子进程便会变成僵尸状态。久而久之,便会造成内存泄漏

wait/waitpid的头文件:

#include<sys/types.h>

#include<sys/wait.h>

阻塞/非阻塞:为了完成操作发起调用,但是当前不具备完成条件时,阻塞型函数一直等,等到操作完成,非阻塞型函数会立即报错返回

 

wait函数:

进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。

pid_t wait (int*status) //阻塞
1.返回值:成功返回pid,失败返回-1
2.参数:用于获取子进程的退出状态,不关心可以设成NULL

waitpid函数:

从本质上讲,系统调用waitpid和wait的作用是完全相同的,但waitpid多出了两个可由用户控制的参数pid和options,从而为我们编程提供了另一种更灵活的方式。

pid_ t waitpid(pid_t pid, int *status, int options) //默认阻塞但可以改成非阻塞
    pid:        
         Pid=-1,等待任一个子进程。与wait等效。        
         Pid>0.等待其进程ID与pid相等的子进程。    
    status:同上
         WIFEXITED(status)	  如果子进程正常结束,它就返回真;否则返回假(查看进程是否是正常退出)
         WEXITSTATUS(status) 如果WIFEXITED(status)为真,则可以用该宏取得子进程exit()返回的结束码(查看进程的退出码)
         WIFSIGNALED(status) 如果子进程因为一个未捕获的信号而终止,它就返回真;否则返回假
         WTERMSIG(status)	  如果WIFSIGNALED(status)为真,则可以用该宏获得导致子进程终止的信号代码
         WIFSTOPPED(status)  如果当前子进程被暂停了,则返回真;否则返回假
         WSTOPSIG(status)	  如果WIFSTOPPED(status)为真,则可以使用该宏获得导致子进程暂停的信号代码
    options:       
         WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。
返回值:    
        1.当正常返回的时候waitpid返回收集到的子进程的进程ID;    
        2.如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;   
        3.如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在; 

获取子进程status:

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

如果传递NULL,表示不关心子进程的退出状态信息, 否则操作系统会根据该参数,将子进程的退出信息反馈给父进程。

status不能简单的当作整形来看待,可以当作位图来看待

 

进程的阻塞和非阻塞:

阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回

非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程

 

程序替换:

将代码虚拟地址经过页表所映射的物理区域(代码在内存中的位置)替换成另一块内存中代码的位置,目的是为了让子进程做和父进程不同的事情。新的程序有自己运行的数据,意味着虚拟地址空间中不仅代码段映射位置改变了,而且数据段也需要重新初始化,映射到新程序数据段的位置(回顾fork创建子进程使用写时拷贝技术的目的:就是为了防止这种情况下空间的白白开辟,以及数据拷贝时间成本)

 

替换函数exec函数族: execl execlp execle

execv execvp execve

l和v的区别:命令行参数传递不同,l-参数平铺,以NULL结尾 v-字符串指针数组

l/v p e 的区别:l/v需要传递可执行程序文件全路径名,lp只需要传递文件名,le传递全路径,并可以自定义子进程环境变量

 

l(list) : 表示参数采用列表

v(vector) : 参数用数组

p(path) : 有p自动搜索环境变量

PATH e(env) : 表示自己维护环境变量

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

exec函数只有出错的返回值而没有成功的返回值,如果调用出错则返回-1

 

简易shell的编写流程:

1.读取输入缓存区

2.对输入数据进行解析

3.创建子进程

4.替换子进程

5.父进程等待子进程退出

fflush:刷新IO缓存区,使缓存区的数据立即显示到屏幕上

 

minishell中添加重定向功能:

1.创建一个子进程对命令进行解析,用指针进行切分,重定向前的是命令,重定向后的是目标文件

2.用句柄fd打开一个文件,

 

scanf("%[^\n]%*c"):

%[^\n]: scanf 取数据的时候遇到各种空白字符就会停止读取,为了读取所有的输入,让scanf遇到换行符再终止读取

%*c:scanf读取数据之后,缓存区中遗留换行符取不出来,导致scanf非阻塞,陷入死循环,所以取出一个字符并丢弃

scanf的返回值:读取数据的个数,对scanf返回值进行判断主要是如果为了避免读取失败,缓存区中的换行符取不出来,陷入死循环的情况(防备直接回车的情况)

 

复制文件描述符:

int dup(int oldfd); int dup2(int oldfd, int newfd);

dup2()与dup()的区别在于可以用newfd来指定新描述符数值,若newfd指向的文件已经被打开,会先将其关闭。若newfd等于oldfd,就不关闭newfd,newfd和oldfd共同指向一份文件。

dup2(fd, 1)的意思是,newfd指向oldfd句柄指向的文件描述符结构,即原本是指向标准输出文件描述结构体的1指向了test.file,这样一来,原本输出到显示器终端的字符串就打印到test.file文件中了,这也是Linux操作系统的重定向实现方法。

 

获取环境变量:

1.main函数的第三个参数法(char* env[ ])

#include <stdio.h> int main(int argc, char *argv[], char *env[]){ int i = 0; for (; env[i]; i++){ printf("%s\n", env[i]); } return 0; }

2.第三方变量environ

#include <stdio.h> int main(int argc, char *argv[]){ extern char **environ; int i = 0; for (; environ[i]; i++){ printf("%s\n", environ[i]); } return 0; }

其中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时要用extern声明

访问、设置环境变量:putenv,getenv

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值