进程概念
1.冯诺依曼体系结构(理解进程前的补充知识)
我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系。
关于冯诺依曼,必须强调几点:
- 这里的存储器指的是内存
- 不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备)
- 外设(输入或输出设备)要输入或者输出数据,也只能写入内存或者从内存中读取。
- 一句话,所有设备都只能直接和内存打交道
为什么所有设备都只能直接和内存打交道呢?
因为外设和CPU的距离非常的远,把你的数据拿到外设在将其发送到输出设备的过程中CPU这个超级快速的东西一直在闲置,一定程度上很浪费,所以引入了一个内存,内存访问CUP的速度就会快非常的多,所以这里在你的外设向CPU发数据的时候,需要进过内存进行一个预加载的过程,然后CPU又会将数据发送给内存,进行一个预写入的过程,这里做到最大程度的对CPU的利用。
2. 操作系统(理解进程前的补充知识)
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:
- 内核(进程管理,内存管理,文件管理,驱动管理)
- 其他程序(例如函数库,shell程序等等)
操作系统是什么?在简单点说:操作系统是一个管理软件和硬件的系统。
为什么要设计有操作系统?
- 与硬件交互,管理所有的软硬件资源
- 为用户程序(应用程序)提供一个良好的执行环境
简单点说:在一套系统中,需要有管理者进行统筹,对上面,给用户一个稳定高效的执行环境,对下层,管理好软硬件资源,提供一个稳定的软硬件环境。
如何理解“管理”?
真正的管理是要具有决策权
计算机管理硬件:
- 描述起来,用struct结构体。(因为Linux下的代码基本都是C语言写的,所以描述一个对象的时候,使用的都是struct所定义出来的。)
- 组织起来,用链表或者其他更高效的数据结构。(先描述,在组织)
所以这里也为我们下面学习如何管理进程埋下伏笔。,基本思想都是一样的
上述表中还需要引入系统调用和库函数的概念
- 在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用。
- 系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者可以对部分系统调用进行适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发。
所以库函数和系统调用是上下级的关系。
3.进程
3.1 基本概念
通俗点说,把程序从硬盘上预加载内存的可以理解为进程。但是呢?这个过程中并非只是简单的把程序变为可执行程序就结束了,实际上进程:可执行程序与管理进程需要的数据结构的集合。
3.2 描述进程—PCB(Process control block)
一个系统可以同时运行多个进程,那么就需要有管理进程的。
- 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
- 课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct
task_struct是PCB的一种
- 在Linux中描述进程的结构体叫做task_struct。
- task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息(这也就呼应了前面的操作系统部分所提出的,任何一个需要被管理的都需要先描述,在组织的过程)
task_ struct内容分类
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
3.2 查看进程
①ps aux | grep mybin
运行的可执行程序叫做mybin,在他一直while循环的过程中,执行上述的操作,便可以查看到此时这个进程的信息。其中这个12791为这个进程的PID(相当于一个身份编号,且这个编号会随着程序的结束而消失,下一次在运行这个可执行程序的时候,PID编号也会随之改变)
②ls /proc/
这个命令可以查看当前所有的进程。你可以看到在mybin的可执行程序一直运行的时候,12791也一直存在,但是一旦这个可执行程序停止时,12791就会在进程中消失。
再次运行可执行程序:
此时同样的可执行程序已经改变了PID编号。
3.3 通过系统调用获取进程标识符
进程id(PID)
父进程id(PPID)
此时你就会发现,你的可执行程序每关闭一次,前面的数字就发生一次改变,但是后面的数字始终保持不变。为什么呢?这里就引入了父子进程的概念(可以理解为父进程是一个公司的boss,子进程是他的员工,对于一个公司来说,不管出现任何的情况,只要boss还在,那么公司就不倒,但是员工可以一直改变,来帮助这个boss干事情,所以一般情况下boss都不会直接出面解决问题,都是让员工也就是这里的子进程去进行一系列的操作。)