1.引入
首先我们知道现在我们使用的大部分计算机都是采用冯诺依曼体系结构的
由五大部件组成 输入设备 输出设备 存储器 运算器和控制器
其中存储器指的是内部存储器 运算器和控制器都集成到了cpu上
而这个系统的管理者就是操作系统(os) 每个电脑设备需要正常运行都需要一个管理系统来进行管理 软硬件进行交互
而os管理所以资源都遵循 先描述后组织
描述(使用struct结构体描述所有的参数)
组织(使用某种数据结构(如链表 顺序表)把每种资源联系起来)
2.进程概念
程序的一个执行实例,正在执行的程序等
而其描述进程的结构体一般叫pcb linux的pcb名为 task_struct
这个结构体里就有各种整个进程的各种信息
当程序被执行 其信息被载入内存 os就会先在内存中创建其pcb
每个进程都有标识符 pid 就是一个数字
进程之间相互独立 互不干扰
进程的状态
cpu每次只能执行一个语句 所以每次也只能有一瞬间也只能有一个进程在执行 不过由于cpu执行速度非常的快 可以在不同进程间迅速切换
进程共有7种状态
R 运行状态 表示进程处于运行或者运行队列中
S 睡眠状态 表示进程正在等待事件完成 (为可中断休眠)
D 磁盘休眠状态 这个状态通常是等待io结束 (为不可中断休眠)
T 停止状态 需要进程停止可以向进程发送SIGSTOP信号 而要让进程继续运行可以发送SIGCONT信号
X 死亡状态 这个状态只是一个返回状态 在任务列表已经看不到了
Z 僵尸状态 这是一个比较特殊的状态 就是它已经退出 但是父进程一直没有获取它的返回值 这段时间它都属于 僵尸进程
t 追踪状态 当进程被调试 停在断点处
僵尸状态的危害
由于进程的完成情况必须被知晓 所以在退出信息没有被接受的情况它的数据一直会被保存在内存中 一直占用内存 可能会造成内存泄漏
还有一种情况就是 孤儿进程
当父进程已经退出 而子进程还在执行 那么这个子进程就会变成孤儿进程
但是孤儿进程都会被1号init进程所领养 并由inin进程回收
3.查看进程
查看系统中的进程 都存放在根目录的proc文件夹中 我们可以ls /proc查看
前面的一堆数字就是一堆正在运行或者等待的进程
(ps 可以查看当前进程的状态 grep 可以查看文件里符合条件的字符串)
其中几个比较重要的参数
uid 执行者的代号
pis 进程的执行号
ppid 父进程的执行号
pri 进程的优先级 值越小 越先执行
ni 进程nice值 可用于调整pri值
4.创建进程
fork函数可用于子进程创建
fork会有一个返回值 如果创建子进程失败 将返回一个负值 如果成功 对于父进程 将返回创建的进程的进程号 对于子进程将返回 0
当程序调用fork()时 系统会做什么事呢
1.为子进程创建新的内存块 和内核数据结构
2.将父进程的部分数据结构的数据拷贝给子进程(例如 数据 环境变量等)
3.将子进程加入到系统进程列表
这里我们使用程序看一下创建子进程的效果
我们还需要使用两个函数辅助一下
getpid可以查看当前进程的pid getppid可以查看当前进程的父进程的pid
可以看到 代码中并没有循环 只有if判断语句 但程序却打印了两个printf语句
为什么一个变量可以满足两个判断语句呢 我们不妨在判断语句内打印变量地址看看
为什么会这样呢
首先 我们看到的进程中的地址其实都是假的
其中每个进程都有一个对应的task_struct 用于描述进程
一个mm_struct用于划分虚拟地址空间
而我们创建的变量和数据就会从这里拿到对应虚拟空间 如静态变量 全局变量 放在静态区 动态申请的空间在堆上 普通变量在栈上 代码和可读常量放在代码区
一个页表 mmu 它就是用来对应虚拟地址和物理地址的 他们一一对应
而物理地址才是内存的真实地址
这里就是发生了写时拷贝
写时拷贝
当创建子进程的时候 子进程将会得到和父进程一样的代码 在双方都还没有对变量修改时 他们是共用一份代码的(就是页表中虚拟地址对应的物理地址一样) 当哪里需要修改变量就会发生写时拷贝 os会给他开一个新的空间 然后修改一下页表对应的地址就行
5.进程返回值
每个进程都有返回值 来表示其执行结果
执行成功 结果正确或失败 执行失败 而这三种状态怎么判断呢
采取退出码+信号的形式
如果父进程一直在运行 而子进程已经退出 但父进程没有接受其退出码 就会像这样 产生僵尸进程
使用我们要学习接受进程返回值
接收进程返回值有两个函数
wait函数 一个输出型参数 status 它是一个位图形式的数据 如果不在乎程序怎么退出可以传NULL 返回值 获取成功就会返回回收的子进程的pid 失败就会返回-1
waitpid 有三个参数 第一个参数就是需要等待的子进程的进程号
第二个就是输出型参数 status 一样的如果不在乎结果可以传NULL
第三个参数 表示 是否需要一直等待子进程返回
WNOHANG表示不等待(非阻塞式等待) 0一定要等待到子进程的返回信息(阻塞式等待)
返回值和wait一样 获取成功就会返回回收的子进程的pid 失败就会返回-1
其中 status
为位图型 它有32位
其中低七位表示退出信号 次低八位表示退出码
其中提供了函数来提取这些信息
wefexited获取信号 当型号为零表示正常退出 非零的有很多种情况 大家可以自行百度
wexitstatus获取退出码