0.前言:冯诺依曼体系结构
- 冯诺依曼体系结构
电脑中涉及两种类型信号:控制信号、数据信号-
计算机硬件构成:
输入设备:显卡、
输出设备:显示器、
存储器(内存):磁盘不算,磁盘算外部设备,且既可做输入,也可做输出。+ 存储介质影响很大,离CPU越近存储效率越高,价格越高。 1. 寄存器(离CPU最近),然后是高速缓存L1、L2、L3。 2. 主存 :CPU可以直接随机存取:RAM【CPU随时读写速度快】。ROM【CPU只读,断电也不消失】。 3. 二级存储【本地磁盘】
-
- 内存和CPU当中
运算器&&控制器(合称CPU):光刻机- 为了效率,CPU不能和输入输出等外设直接交互,使用中间设备内存,提高效率。但还不够快,后来就使用寄存器和CPU交互,寄存器和内存交互。所以一般写入内存,内存再刷新给外设【该过程叫output,而输入叫input,两者相加=IO】。【有了内存,CPU就不用和外设打交道】。
结论:内存是体系结构的核心设备。
因为任何外设,在数据层面,基本优先和内存打交道。
且CPU在数据层面上,也直接和内存打交道。
网卡:两个设备聊天发送信息,通过网卡
- 【操作系统】:对专门对软硬件资源进行管理工作的软件。把软件数据与代码加载到内存中。
为什么要操作系统,对下管理好软硬件资源,对上给用户提供稳定高效安全的运行环境。 - OS怎么办?管理:决策、执行
- 但是管理者和被管理者(或者说决策者和被决策者)从来都不是直接交互,操作系统也是这样,操作系统管理硬件通过驱动程序。每一种硬件都有自己对应的驱动。除了硬件,操作系统也管理软件:分为四大块:进程管理、内存管理、文件系统、驱动管理。这四大块为了方便操作系统间接对用户、程序员、其他进行管理。*此外,决策不是凭空产生,而是通过数据做决策。
- 数据结构是操作系统理解的关键。因为操作系统要管理需要:先描述再组织。
- 进程管理需要有PCB,为什么要PCB,因为需要【先组织,再管理】。
- 管理的理念:先描述、再组织。
操作系统不信任系统,所以有系统调用接口【大白话:OS提供的接口就是写的函数】让用户直接操作。但是系统提供的接口过于复杂。于是有了语言和第三方库。方便人们各组操作使用操作系统并使用计算机资源。操作系统对软件做管理,进程就是OS管理的范畴。简言之,OS对软件管理需要通过进程。
1. 进程:加载到内存中的程序
关于进程:
- 进程管理是什么?
答:进程的状态何时改变且变为何状态、何时违规该杀掉等都叫进程管理。 - 如何管理进程:先描述,后管理。
答: 进程在形成之时,操作系统要为进程创建PCB【进程控制块】。进程控制块就是描述的过程。它像个结构体。操作系统要创建进程必须先创建PCB。 - PCB是什么?
答:操作系统上,PCB叫进程控制块。语言上,就是一个结构体类型。【在windows和Linux下都不错】,在Linux下进程总称PCB,具体的每一个叫struct task_struct,像shell和bash一样。
进程和程序的区别: - 如何查看进程?
答: ps axj | grep “myproc”:查看进程并查找其中“myproc”字眼的进程。 - 程序和进程的关系?
运行程序本质是在OS创建进程,所以运行程序的说法不准确,应该是叫运行进程。 - 进程 vs 程序
程序本质是文件。把文件夹着到内存,就叫进程。你的进程对应的文件(可执行程序文件)必须也被加载到内存。必须先描述再组织,把二进制文件夹着到内存,创建进程时,还要创建一个PCB【task_struct】,进程控制块。task_struct和可执行文件被统称为【进程】。
【进程】 = 程序文件内容+相关数据结构(暂时没学与进程相关的数据结构,特制为了维护进程所创建的数据结构)。每个进程有一个PCB。
PCB的task_struct包含了进程所有属性【描述】。并且可以通过它找到进程代码和数据。找进程不是找进程加载到内存的代码和数据,而是找它对应的task_struct。
进程 = 代码+操作系统维护进程的相关数据结构。
操作系统找进程不找进程中加到内存的代码和数据,而是找进程的描述信息。
CPU要进程,操作系统给CPU也就是进程的task_struct的结构体变量给CPU。有了变量也能找到描述属性,也能找到内存中进程的代码和数据。
**有了进程控制块,所有的进程管理任务与进程对应的程序毫无关系。**所有进程管理任务与进程对应程序毫无关系,与进程对应的由内核创建的进程的PCB强相关。
- PCB的内部构成
给进程发送信号
- 通过标识符PID :ps axj中的PID
kill -9:8086干掉8086对应的进程
ppid:获取父进程pid
同一个程序,启动起来每次程序不一样。
直接通过grep pid号就能得到这个进程.bash
在命令行上运行的命令,基本上父进程都是bash。
进程状态:任务状态、退出代码、退出信号
I/O状态:给进程分配的I/O设备。【文件操作的本质是进程在操作,进程在进行IO】
记账信息:CPU内或OS内有负责进行调度的单元。较为均衡的调度每个进程。【调度】模块让系统公平分配资源。而记录历史上进程享受过进程用过的资源信息,就叫记账信息。
- 为什么C程序最后都是return 0
进程退出码:exit_code,会返回给父进程。
echo $?:显示进程退出码,会显示最近一次执行的命令返回的退出码。
上下文数据:
一个CPU,但多个进程,谁先上?【排队的本质就是优先级】
CPU内有一个寄存器:pc指针。代表内存中一块地址。
CPU如何知道第一行,然后再做第二行。因为PC指针指向即将执行的下一条指令的地址。CPU做完这次任务先先找寄存器PC指针,做完寄存器指针会PC++。 - 上下文:
CPU内包含很大大小不一的存储单元【寄存器】,寄存器保存的是当前正在运行的进程的临时数据。
进程的阻塞、挂起。
进程的代码可能不是很短的时间就运行完的,规定每个进程单词运行的时间片。过完规定时间片,给另外一个进程。一个进程单词运行最长时间。因为时间片和CPU的快速切换,即使只是单CPU情况时也使得用户感受到是同时在执行多个任务。
进程之间有切换,进程可能存在大量临时数据。【暂时存在CPU的寄存器中】。如果某个进程的临时数据太多了寄存器会不会满。当一个进程走的时候,应该保存好自己之前的数据。使得轮转到没执行完的旧进程再运行时可以直接使用旧的临时变量。之前的旧数据就是上下文,如果**但是进程来时,还要恢复上下文,不是直接能用。**具体过程:进程走的时候,先把临时数据保存在PCB中,然后再走,即【自己拿着上下文,并不在寄存器中】。通过上下文的保护使得能感受到进程是被切换的。
PCB中进程代码特别多。 - 操作:
ctrl+L、J、K、H选中区域,按住大写I,双斜杠,ctrl+D,批量化取消注释。
【查看进程】
- ps命令
- ls -d /proc 查看进程的目录
进程启动后会在 /proc下形成目录,以自己的pid号形成目录。
ls -al:查看进程中全部内容
其中有个exe:当前正在执行谁
cwd:当前工作目录
你自己在程序运行时写创建个文件,当前会在路径下创建,如何知道当前路径的,就是利用这个cwd当前路径下创建文件。
最后再总结,1.进程是加载到内存中的程序,操作系统为了管理该进程,系统本身为该进程创建大量的数据结构来表示该进程。
2. 进程= 内核描述进程相关的数据结构+进程的代码和数据。
3. 为什么需要进程:
4. 为什么要PCB:OS要管理操作对象。为了管理进程,必须要有管理进程的相关数据结构。
进程的状态
进程是动态的,因为它的状态可以做切换。
- 就绪态、运行态:都称为R运行状态。
- 停止:是X(死亡)或Z(僵尸)。
- 阻塞(挂起):S、D状态。
- R、S、T:
从一款具体操作系统状态去研究才能学懂操作系统。
-
进程的信息状态在哪儿?PCB
-
进程状态的意义:方便操作系统快速判断进程,完成特定功能,比如调度。【操作系统完成特定功能需要判断区分不同进程的状态好去完成任务】。
-
R:运行态、就绪态都为R状态。运行态说明进程已经在占有CPU资源,而就绪态相当于在等待处理机资源,因为CPU忙不过来。
-
S【sleep】:想从网络中读数据,但是网络中没数据,想给磁盘写数据,但是磁盘满了。当我们想完成某种任务时,任务条件不具备,进程在进行等待,可能等某一事件发生(即使有资源也不行),或某一资源被释放(某一资源CPU或外设均可)。:S、D
当有多个进程在等某种外部资源设备,谁在等?一定是PCB在等。当前进程在等,比如你写C程序,需要输入但不输入,但是此时可能别的进程也在等。但排队是PCB在排队,进程在等待,不可被执行调度。。 这些进程处在:wait_queue。
从上,不要认为进程只会等待CPU资源,也会等待外设。进程可以等待一切资源。**等待CPU资源时,叫运行队列,而等其它资源,叫等待队列。**当资源一旦可用,把该进程改为SR状态,放到CPU的运行队列:R队列。这个进程就可以调用设备了。【进程等,不能在CPU等,把它从CPU剥离下来,放到S队列。】所以,进程在运行时,因为运行需要,可能会在不同队列里。在不同队列里,所处的状态是不一样的。在不同队列里,所处状态是不一样的。有时候你的软件比如网易云卡死了,可能因为异常时,某些资源拿不到,进程长时间得不到资源,在等待队列中。因为CPU不跑它了,这个软件没有被运行。 -
从运行状态的task_struct放到等待队列,从运行状态放到等待队列中,就叫挂起。
-
**从等待队列,放到运行队列,被CPU调度就叫唤醒进程。**比如代码中sleep,就是进入了等待状态。
-
S状态叫做可中断睡眠。
冯诺依曼告诉我们:程序读数据需要从外设读入内存中。 -
D:D状态叫不可睡眠、深度睡眠,也叫一种S状态。一般S是浅度睡眠。不可以被唤醒。,D状态不可以被杀掉。为了避免过长等待,被操作系统发现过久、或在繁忙时无意义占掉内存而杀掉。
-
T:彻底暂停,没有数据交互。
-
t:追踪。典型应用:运行程序时打个断点被暂停的进程,看变量。
-
X:死亡。回收进程
-
Z(zombie):僵尸状态。 僵尸进程应该回收。根据进程的退出信息辨别死亡原因。
-
如上,左侧运行一个与外设交互的例子,循环打印,但是右边发现只有一开始是R运行状态,后面都是S,为什么?
因为CPU运行太快了,和IO交互在CPU看来很慢,所以这个进程查看时因为与外设交互而总是被挂起的,只有很短时间在运行。 -
给进程发信号:
kill -l:查看信号
kill -19:STOP信号
kill -9:KILL 干掉进程
kill -18:continue
僵尸进程:常在子进程上
- 为什么要有僵尸状态?
为了辨别进程退出的死亡原因。 - 为什么可以辨别进程退出信息?
系统会将系统退出的所有信息写在PCB,供系统或父进程去做读取。 - 什么是僵尸进程?
进程退出,但是部分资源像PID不被回收,就一直处于僵尸状态。检测和回收方:父进程。
Z->X->被收回(pid等信息) - 标志:
处于Z状态的就是僵尸进程。
kill -19 暂停成T
kill -18 干不掉 成了S
它现在成了后台进程,干不掉了。只能kill -9
前台:S+,带加号
./mycode.c & 这样运行起的进程是后台进程。不能ctrl+c停
后台:ctrl+C 不能停止的进程。
实验:模拟生成僵尸进程
- 写C++程序区分父子进程。
- 监控进程命令行脚本:
while :; do ps axj | head -1 && ps ajx | grep mycode | grep -v grep; sleep 1 ; echo "######################"; done
执行后,监控中还没有进程
-
运行C++程序并观察监控,监控到了进程
所以,27934是子进程。
【回忆】:
疑问:运行中的进程,为什么大部分时间状态是S小部分是R?
答:因为CPU处理速度超快,而输出是外设的事,很慢,所以大部分时候该进程是S:休眠状态,但少部分时候能捕捉到进程是运行 态。 -
杀死子进程 。
-
此时发现了进程状态为Z:僵尸态
- 扩展:僵尸态的坏处:
答:所有进程死掉,Linux操作系统会释放它的资源,但是会保留部分信息,比如PID,父进程也没有去使用wait或waitpid方法清理PID,这就造成了僵尸进程。操作系统中存在PID,PID被占用,但又没有进程在用。像人死了,身份证号没删除。且僵尸态过多,使得操作系统CPU、内存等资源发现没有被占,但是又什么都做不了。因为PID都被占用了。
孤儿进程:
和僵尸相反,子在运行,而父先死,子一直在运行,子从S+成了S。子进程的PPID成了1,子进程会被1号进程领养,1号进程是操作系统,这种情况的进程状态称为孤儿进程。
进程状态带+和不带+:前台和后台的区别。
前台运行:./去运行,可以ctrl+c停止。
后台:当前看不见不能用ctrl+c停止,只能用kill -9去杀掉。
R代表运行,但不代表一定在运行,它可能处在CPU运行队列中等待。
进程具有独立性。像某个软件挂掉,其它软件并不会挂,互不干扰。
并行和并发:系统中有若干进程,且有几个CPU,进程分别在不同CPU上运行,这叫并行。服务器一般双CPU。而并发是1个CPU下采取进程切换的方式,让多个进程得以推进,称之为并发。区别是:并行同一时刻同两个以上在跑。并发是多个进程切换。一般情况下自己的电脑上都是进程切换的并发。
模拟孤儿进程
- 如之前,先打开监控进程命令行:
- 写C++源码:让父进程休眠10秒后退出。此时子进程的父进程由原来变为了1(init),其实就是操作系统
状态如下:
孤儿进程无危害,操作系统自动会回收。