一个程序从磁盘以文件的形式加载到内存之后,已经变成了进程!
引入管理者和被管理者
1、管理者和被管理者不需要见面!(例如学生和校长!)
2、管理者在不见被管理者的情况下,如何做好管理呢?只要能够得到管理信息,就可以在未来进行管理决策!(管理的本质:通过对数据的管理,达到对人的管理)
3、管理者和被管理者面都不见,怎么才能拿到数据?
通过辅导员(本质上也是执行者 ---> 执行校长的命令)
例如网卡出现问题,这时,驱动程序会将有问题的数据报告给操作系统,此时操作系统检测到硬件网卡出现问题,操作系统自动修复,如果修复不了就向上报给用户说明故障!
如果学生(硬件)太多,此时操作系统会将学生按照结构体的类型整理起来!
类似于链表结构!此时10000个学生就会有10000个结构体对象!
此时,成功的将对学生(硬件)的管理工作,改为对链表的增删改查!
软硬件的数量太大!此时操作系统会根据软硬件的属性进行分类(描述的过程),然后再将分类好的结果按照数据结构的类型进行管理(组织的过程)!
在操作系统中,管理任何对象,最终都可以转化为某种数据的增删查改!(先描述再组织!)
先描述再组织:面向对象编程的核心思想也是!(例如clsaa类)
操作系统改成为硬件的管理对链表的增删查改(这一过程称为---建模)---> 计算机只能这么做!
操作系统中一定存在了大量的数据结构!
如果我们使用printf函数打印东西到显示器上面!(这个过程是从上到下依次贯穿的!)
因此对于C/C++的库函数(lib)和系统调用的关系是上下层的关系!(上下层的调用和被调用的关系!)
总结:
1、计算机管理硬件
- 描述起来用struct结构体(因为操作系统就是C写的!)
- 组织起来,用链表或者其他高效的数据结构!
2、系统调用和库函数
- 在开发角度,操作系统对外会表现为一个整体,但是会暴漏自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用!
- 系统调用在使用上,功能比较基础,对用户的要求相对比较高,所有,有心的开发者对部分系统调用进行了适度的封装,从而形成了库!有了库,很利于更上层用户或者进行二次开发!
一、再谈进程
1、引入
如果进程有成千上百个,操作系统怎么对进程进行规划呢?
也是先描述再组织!!!
一个被加载到内存中的程序,也叫做进程!(进程也叫任务)
也有的教材说:正在运行的程序叫做进程!
正常情况下我们写的myprocess.c和myprocess可执行程序都位于磁盘当中!
此时如果我们运行./myprocess,就会形成一个进程!
开机的本质就是把操作系统从外设搬入到内存当中!!!
就例如我们如果想要运行./myprocess,需要将其加载到内存中,再由CPU进行处理!!!
一个操作系统,不仅仅只能运行一个进程,还可以同时运行多个进程!
操作系统必须对所有的进程管理起来!如何管理呢?---> 先描述,再组织!!!
任何一个进程,再加载到内存的时候,形成真正的进程时,操作系统要先创建描述进程的结构体对象------PCB(process ctrl block)------ 进程控制块
人是怎么辨别一个事物或者对象的?(通过属性认识的!!!)
当属性够多的时候,这一堆属性的集合,就是目标对象!!!
同样的,描述一个进程的时候,如果进程的描述属性足够多,那么我们就可以确定具体的进程!!!(本质就是面向对象!!)
因为操作系统是C语言写的,所有进程本质就是操作系统中的一个结构体类型!!!
PCB是一个结构体,里面存放用于区分不同进程的属性,例如:进程的编号,进程的状态,优先级,相关的指针信息(通过指针找到对应的代码和数据),(struct PCB* next)(可能是以链表的形式进行描述多个进程的)......
PCB也被加载到内存中!而当我们运行一个可执行程序,代码和数据可会被加载到内存当中!此时,我们可以自己给进程一个定义:
内核PCB数据结构对象 + 自己的代码和数据 ---- >进程
但是通常操作系统管理进程不看代码和数据,仅仅是通过PCB对象来管理!
当有多个进程的时候,操作系统会根据PCB创建对应的PCB结构体对象!这个结构体对象可以找到自己原来的代码和数据!
此时,在操作系统中对进程的管理变成了对链表的增删查改!!!
因此,此后操作系统对进程管理都是对PCB结构体对象进行管理!!!
上述步骤,任何操作系统都是这样子定义来的
2、那么具体Linux是怎么实现的?
在不同的操作系统,windows/Linux/mac实现的差别有所不同!
课本上称之为PCB,但是在Linux系统中称之为PCB:task_struct;
task_struct是PCB的一种!
- 在Linux系统中描述进程的结构体叫做task_struct;
- task_struct是Linux内核的一种数据结构(一种自定义类型),它会被装载到RAM(内存)里并且保存进程的信息!
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。(唯一的一个编号!)
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。(进程在运行的时候会经常被其他事物影响而停止或者中断,此时记录下运行到当前位置的地址,方便后面接着运行!)
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针(方便找到对应的数据)
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
小总结:
- pcb -> task_struct 结构体里面包含了进程的所有属性;
- Linux中如何组织进程 ---> Linux系统中,最基本的组织进程采用task_struct的方式,采用的是双链表组织的(一个PCB对象可能不止在链表中,还有可能在二叉树等其他数据结构中!)
例如使用PCB_*next链入链表;使用PCB_*queue链入队列;
对进程的管理工作,取决于将进程放进那个被管理的数据结构类型中!
3、查看进程的相关属性
ps命令可以查看属性;
运行两个一模一样的程序会生成两个进程!
- PID就是其中进程唯一的ID值,用于区分不同的进程;
Linux系统中存在一个目录
ls /proc
可以通过 /proc查看当前系统下的所有进程;
下面的grep -- color=autor 实际上就是grep对应的进程!
grep的关键字里也有process,因此当它在执行过滤系统当中的进程时,首先会把自己变成进程,然后自己才会被CPU调度,执行自己的过滤代码!
通过ls查看会发现根据ID号码排列的一个个目录, 系统当中启动的所有进程,默认会在 /proc下面创建一个以该进程PID命名的文件夹!该目录下保存了进程的大部分属性!
ls /proc/20639
可以改看该PID下进程的相关信息
如果此时再将程序关闭,会发现文件夹消失!
再次运行后进程的PID号码发生改变!(大概率会发生改变)
proc目录中包含的是系统动态目录下的相关进程的信息!
cwd --- > current work dir 指的是当前进程的工作目录
在C语言中,如果使用fopen创建一个文件,这个文件一般在当前目录下存放!
且为什么在一个目录下touch test.c是在当前目录下创建的?
实际上,当touch这个指令运行起来变为进程,默认进程在哪个目录,这个进程所在的目录就是当前目录!(PCB属性会记录当前所在的Linux的绝对路径为但当前路径!)
实际上fopen在运行的时候会将"log.txt"拼接到cwd的后面!