目录
2.3、操作系统怎么完成这些事情的(怎么管理软件硬件资源的)
1、冯诺依曼体系结构
1.1、结构介绍
[1] 运算器(CPU):CPU中央处理器是用于处理算数用算和逻辑用算的,算数用算就是加减乘除运算,而逻辑运算就是与运算,或运算,还有我们语言中的if,for,while其实都是逻辑运算。
[2] 存储器:是内存,并非是磁盘等。所有的数据都是二进制存储的,运算产生的数据都是存储在内存当中。
[3] 输入设备:键盘,鼠标,扫描仪,网卡等。
[4] 输出设备:屏幕,网卡,打印机等。
1.2、那他们之间是怎样工作的呢?
例如从输入设备输入一个数据,会经过存储器然后被cup读取进行运算然后写回到存储器中,最后显示到输出设备上。
2、操作系统的概念与定位
2.1、操作系统是什么?
[1] 操作系统=操作系统内核+一堆应用。
[2] 操作系统内核:也是代码程序,代码的作用就是(进程管理,内存管理,文件管理,驱动管理等等)。
[3] 一堆应用:依附在操作系统用内核上完成某些功能,例如:QQ,微信,飞书等等。
2.2、操作系统在做什么事情
[1]、操作系统在管理计算机的软硬件资源
(1)硬件资源:CPU,内存,硬盘,网卡,显示器等等
(2)软件资源:进程资源,驱动资源
2.3、操作系统怎么完成这些事情的(怎么管理软件硬件资源的)
[1] 通过管理:管理=描述(结构体)+组织(串联结构体)
(1)说到结构体是描述这里可能你就会蒙圈了,结构体不就是一个由多个相同或不同数据构成的集合吗?为什么这里要叫描述。其实如果你对结构体深入理解和应用就会知道,结构体其实就是一个描述一个对象的集合,在这个结构体中存储着结构体对象的各种数据特征,比如说我们定义了一个描述学生的结构体,那结构体中的数据都是关于这个学生的特征信息,所以我们吧结构体也称为描述.。
(2)组织就是我们说的数据结构,像链表,二叉树等等数据结构。用这些数据结构将结构体链接起来以便操作系统进行管理。
2.4、操作系统组织结构图
2.5、系统调用&库函数
[1] 系统调用函数:操作系统内核提供的函数,被称之为系统调用函数。
[2]库函数:C标准库提供的函数,称之为库函数。库函数的代码实现当中调用了系统调用函数。这里有个疑问:为什么有了系统调用函数还要有库函数呢?这是因为系统调用函数一般都参数生僻不是特别的只管,我们在写软件进行调用的时候可能会不方便,所以就有一群人将一些难用的系统函数进行封装。(所谓封装通俗的理解就是基于系统函数之上再写一个函数,这个函数的传参会更明了一些,将这些参数在这个新的函数中进行处理然后传给系统函数从而实现函数功能。)后面我再写进程间通信的博客中会用到系统调用函数,到时候你会对系统调用函数有更深的理解。点歌关注不迷路。
2.6、什么是程序?什么是进程?
[1] 程序:源代码经过编译产生的可执行文件,这个文件是静态的。
[2] 进程:程序运行起来的实例,是动态再运行的。通俗来讲就是正在运行的程序。就叫做进程。
2.7、操作系统是如何来管理进程的?
[1] 进程的管理和之前我们说的操作系统的管理有些相似
[2] 进程的管理=描述(PCB)+组织的方式(双向链表)
2.8、描述(PCB)
[1] 什么是PCB?
PCB:process ctrl block(进程控制块)
在操作系统代码当中是一个结构体:struct task_struct{...}
[2] PCB当中的内容(也就是这个结构体当中的内容)
(1)进程号(PID)(进程标识符):
1、 作用:表示当前在操作系统当中的一个进程。
2、 在当前操作系统中,一个进程拥有的进程号是唯一的。也就是说在每个进程描述PCB中其PID都是不一样的,不能出现两个进程中PID一样的现象。
3、进程号可以重复使用,就是说当一个进程结束之后他的PCB会在内核中销毁,销毁之后其他新的进程就可以用他的进程号。
4、在Linux中查看进程号
ps:查看当前操作系统中的进程信息的命令
ps aux:
ps -ef:
getpid(函数可以用man命令在二号手册中查出,(注:二号手册中查出来的都是系统调用函数))
4.1、ps aux:我们执行可以发现它输出了当前所有进程,我们要想查看特定的进程还需要翻找,这不利于我们查看特定的进程信息。
所以一般我们配合管道进行使用 ps aux | grep [可执行程序名]我们创建一个程序这里要一个死循环让他一直运行,要不然程序就会退出
这里输入ps aux | grep pid_look,就可以看到我们的pid _look这个进程的pid了
4.2、ps -ef命令
作用查看进程pid和其父进程pid(父进程在下面fork函数出会讲到)
同样也可以配合grep使用。 例如查看我们的test_getpid进程的进程号和其父进程的进程号。
4.3、getpid函数
1、函数功能:谁调用获取自己的PID(进程号)
2、pid_t:内核定义的进程号的类型,这个类型本质上就是整型(int)没有参数。
3、返回值:返回当前调用”getpid“函数的进程的进程号
可以看到输入命令ps aux|grep test_getpid进程号是5133
调用函数getpid返回值就是进程号5133
(2)进程状态:就绪/运行/阻塞
- 运行:进程占用CPU,并在CPU上运行;理解为进程正在使用cpu来执行自己的代码
- 就绪:进程已经具备运行条件,但是CPU还没有分配过来;理解为进程已经将运行前的准备工作全部做好了,就等着操作系统调用,占用CPU了,只要操作系统一调用就会变成运行状态。
- 阻塞:进程因等待某件事发生而暂时不能运行;例如:等待IO输入(例如一个函数中写了scanf那么在它就需要用户给他输入参数才能继续往下走),调用某些阻塞接口。
- 三种状态之间的转换
(3)细分的进程状态:
我们通过ps aux查看PID时可以看到后面有一列叫做STAT这就是进程的进程状态。
- R:运行状态(代码)
- 处于R状态的进程,有可能在执行代码,有可能在运行队列(就绪队列)
- 我们写一个死循环查看他的进程状态时可以发现是R状态。
- S:可中断睡眠状态(代码)
- 进程正在睡眠(被阻塞),等待资源到来是唤醒,也可以通过其他进程信号或时钟中断唤醒,进入运行队列
- 我们给函数加上sleep函数就可以看到进程处于S状态睡眠状态。
- 为什么程序的CPU使用时间会是0呢?这是因为当前程序使用CPU的时间极短,使用秒这个数量级无法表示。
- 我们查看一下sleep函数输入man sleep可以发现它直接跳转出来的是一号手册(一号手册是命令手册),这时我们需要自己给它加上手册号man 3 sleep
- D:不可中断睡眠状态:通常等待一个I0结束(也就是输入输出结束)
- T:暂停状态(ctrl+z)(代码)
- 处于暂停状态的代码并不是退出了,而是暂时不执行我们的进程。
- 结论:在linux下不要使用ctrl+z结束进程,不是结束,而是暂停。所以要终止一个进程时要按下ctrl+c。
- 那么处于暂停状态怎么恢复运行呢?只要按下fg暂停的进程就会继续运行。
- t:跟踪状态∶表示当前进程正在被跟踪,当调试一个代码的时候可以看到。
- 我们给一个程序加上调试信息
- 我们加上调试信息之后查看代码的状态信息发现状态信息是S,这时需要看清楚这是gdb程序,并不是我们当前的调试程序
- 我们下个断点让他run起来
- 然后查看他的进程信息,我们此时可以发现他的状态信息是t,而且我们看到它前面有一个路径这是因为这个程序并不是我们程序员自己启动的,而是gdb这个程序给了一个绝对路径启动的。
- X:死亡状态:
- 这个状态用户是看不到的,在PCB中被内核释放的时候,进程会被重置为X,紧接着进程就退出了。
- Z:僵尸状态(重点):待定
(4)程序计数器
作用:保存程序下一条执行的指令,为下一次进程执行做准备工作。(这里的程序计数器保存的指令并不是我们的高级语言的代码,而是指的是汇编指令,汇编代码)。
查看汇编指令:在程序中下一个断点让他跑起来,然后输入指令disassemble
ni:按照汇编指令进行单步执行
1、在进程被切换出去的时候会保存现场:程序计数器会保存当前程序执行到了那一步。即将执行那一条指令。
2、在进程再次拿到cpu资源时会恢复现场:根据程序计数器中的指令来获取当前进程下一步要执行的代码。
(5)上下文信息
作用:保存寄存器当中的内容
在了解上下文信息时我们首先要了解一个东西,CPU是怎样从内存中拿到数据进行运算的呢?
我们发现cpu在拿数据的时候并不是直接从内存中拿数据。而是从身边的寄存器中拿数据,这时因为cpu对寄存器的读取速度最快。
总结:所以这里上下文信息是保存的当前程序在运行时寄存器当中的内容,因为寄存器不是进程所拥有的,当他被切换出去时,运行其他进程时当前寄存器当中的内容有可能就改变了。而上下文信息保存当前寄存器当中的内容之后可以在下次运行时快速的找到上一次运行结束时寄存器当中保存的内容。(重点)
(6)内存指针
作用:”指向“进程地址空间”
每个进程的内存指针都指向自己的程序地址空间
(7)记账信息
作用:使用CPU时长,占用内存大小。
(8)IO信息
作用:保存进程打开文件的信息
1、 每个进程在创建的时候,都会默认打开三个文件
1.1 stdin 标准输入: scanf getchar
1.2stdout 标准输出 :printf
1.3strerr 标准错误 :perror
2、验证:
一个进程被创建出来以后,操作系统就会以进程的进程号命名一个文件夹,该文件夹下的内容都是该进程的相关内容。/proc
2.1、我们让程序一直运行
2.2、然后打开另一个窗口
如果程序运行结束之后这个以进程号命名的文件就会被操作系统删除掉,同时PCB也会被释放掉。
2.9、进程式抢占式执行
刚刚看了进程的几种状态,我们可以知道cup数量是远远小于进程数量的但是我们发现在我们的电脑上打开软件时并不会存在那个软件无法打开,这就得益于进程的抢占式执行。
- 在机器的CPU数量少,进程多的情况的(常态),操作系统在调度的时候要做到雨露均沾(这里的雨露均沾意思就是让每一个进程都能够运行)。让每一个进程都能运行上,但是操作系统在调度的时候,是从就绪队列当中获取进程,进行运行。换句话说,进程谁准备好了,谁就绪
- 原则上就可以调度谁。所以,进程为了能够执行自己的代码,都是抢占式执行,不会互相谦让。
- 所以进程就会有不同的状态,其中之一原因就是“狼多肉少”
- 操作系统调度的时候有各种算法:先来先服务,短作业优先,高优先级优先,时间片(毫秒级别:5-800)轮转等等。
- 先来先服务:谁先到先执行谁,先来后到
- 短作业优先:运行时间短的优先被调度
- 高优先级优先:进程的优先级越高被调度的概率越高,高优先级的进程就绪之后可能会将原本在CPU中运行的低优先级的进程剥离出来,从而使低优先级的进程变为阻塞状态或者就绪状态。
- 时间片:给每一个就绪状态的进程在分配CPU资源的时候分配了一个时间片 ,在时间片内,进程可以拿着CUP进行运算自己的代码。时间片到了就会被剥离COU资源。
- 并发:多个进程在一个CPU下,采用进程切换的方式,各自独占CPU运行各自的代码,交替运行,让多个进程都得以推进,称之为并发
- 并行:多个进程在多个CPU下,同时运行各自的代码,称之为并行
- 都看到这里了,不如就点个免费的赞吧,者对我真的很重要!!!