基础概念 / 操作系统

核心:CPU管理、内存管理

img1

操作系统概念

1.操作系统主要内容:定义(CPU管理、内存管理)

  • 定义:用于控制和管理计算机的硬件和软件,合理调度CPU和内存等资源,分配给用户和其他软件的接口和环境
  • 分类:分时操作系统,实时操作系统。
    1. 分时操作系统(windows)——计算机以时间片为单位,轮流给各个用户服务。解决了人机交互问题。(各个用户通过终端与计算机交互)
    2. 实时操作系统(嵌入式):计算机接收到外部信号后及时处理,触发马上反应。(即时性和可靠性)

2.操作系统的基本特性

  1. 并发性:操作系统可以同时运行多个进程。不管是多核CPU还是单核CPU的计算机。(分时运行,分是获得CPU资源)
  2. 共享性:同时运行的进程可以共同使用系统中的资源。(互斥和同步访问)同步也是在互斥的基础上实现的访问机制。
  3. 异步性:进程不是一次性执行完成,而是走走停停的,但是最后结果不变。
  4. 虚拟性:虚拟是指将物理上的一个实体变为多个对应逻辑物。计算机中主要用于时分复用(CPU)和空分复用(虚拟内存)。

补充:并发指的是多个程序同时运行,但是单核CPU穿插运行两个进程,通过时分复用来提高CPU的效率。
并行指的是在多核CPU上分别运行进程,是并行运算提高计算机性能。


3.计算机的主要功能

  1. CPU管理——合理分配CPU资源,进行进程管理:进程同步,通信、调度等
  2. 内存管理——对内存和虚拟内存管理:合理分配内存空间,进程间不发生死锁等异常情况。
  3. 文件管理——系统、用户文件的管理
  4. IO设备管理——对外围设备的管理,分配接口等

进程与线程

线程:是CPU调度的最小单位。

进程:是系统资源调度分配基本单位。

1.进程定义

进程定义:进程是对运行程序的封装,一个进程可以包含一个或多个程序。进程是系统资源调度的基本单位。运行的微信、QQ都是一个进程。

生命周期:(获得其他资源和CPU资源的过程)

  1. 新建:未获得资源
  2. 就绪:获得其他资源,等待CPU资源
  3. 运行:获得其他资源,获得CPU资源
  4. 阻塞:等待触发事件以获得时间片资源,CPU空闲也不会运行
  5. 终止:退出,释放所有资源
    img2

CPU资源以时间片来分配


2.进程和程序的关系

程序由一系列代码组成。而进程由程序、程序包含的数据,进程块组成。
从广度上看,进程是程序的动态体现,程序是进程的静态体现,两者相辅相成。
程序构建进程,进程执行程序。

3.进程间的通信方式——作用——共享内存/套接字/信号/信号量

  1. 管道通信pipe:多用于父子进程间通信
  2. 信号signal:通过接收事件信号,告知进程某事已经发生
  3. 共享内存shared memory:应用最为广泛,进程间通过共享内存上数据的更新,获得信息。
  4. 信号量:用于进程中不同线程的同步
  5. 套接字socket:不同计算机进程间的通信

作用:A.数据传输及共享 B事件通知 C进程控制

4.进程同步 / 调度算法——进程获得CPU资源的先后执行顺序——CPU分配

多进程提高了CPU的利用率,但是进程的异步性会给系统造成混乱。进程同步就是:协调进程间的执行顺序,使得并发的进程间可以有效的共享资源、相互合作。

总结:多进程的异步性造成系统混乱,我们需要协调进程执行顺序,让进程间有效共享资源,相互合作。

进程调度算法:CPU分配算法
主要指标:CPU利用率、系统吞吐量、周转时间、等待时间、响应时间等

  • A.先来先服务算法(FCFS):先来先服务调度算法,队列实现
  • B.短作业优先算法(SJF):优先进行预估时间较短的进程(平均等待时间,周转时间最少)
  • C.优先级调度算法:优先级越高的,先分配到CPU
  • D.最高响应比算法(HRN): 根据响应比决定优先级,响应比=(等待时间+要求服务时间)/要求服务时间;(兼顾长作业和短作业)
  • E.时间片轮转调度(RR): 按到达的先后对进程放入队列中,依次分配相同的时间片,时间片用完,马上剥夺CPU
  • F.多级反馈队列调度算法(较好的算法): 设置多个就绪队列,为每个队列赋予不同优先级,优先级不同分配的时间片也不同。第一个队列优先级最高,分配的时间片也越短。

6.死锁现象 / 处理死锁的方法

死锁现象:多个进程争夺同一资源而陷入僵局,导致无法推进下去,进程无限阻塞,相互等待资源,最后卡死。

死锁原因:进程竞争资源,资源释放不合理

死锁产生的四大必要条件——发生死锁,四条至少一条成立

  • —–1.互斥,2.请求和保持,3.不可剥夺,4.循环等待—–
  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求和保持条件:一个进程申请新资源时,对以旧资源不放
  • 不可剥夺条件:进程获得资源在未使用完前,是不会释放它的
  • 环路等待条件:若干进程之间形成一种头尾相接的环形等待资源关系

处理死锁的方法:打破四大条件

  • 1.互斥条件不可打破
  • 2.打破请和保持条件——实行预分配,只有满足进程所有资源要求时,才分配
  • 3.打破不可剥夺条件——允许进程剥夺其他进程占有的资源,但是降低系统性能
  • 4.打破环路等待条件——对资源进行编号,只有占用了小号资源才能申请大号资源。
  • 基本思想都是:动态检测资源分配,从而保证系统处于安全状态。

最常见的是银行家算法:检查申请者对资源的最大需求,如果各类资源都满足,就分配。这样可以很快完成计算,然后释放申请者申请的资源。

7.临界资源的概念

共享性,让进程间可以共享系统资源。但是有的资源只能被单一进程使用,我们称其为临界资源。比如:打印机

临界资源的访问必须遵循互斥原则,访问临界资源的代码,我们称为临界区。


8.线程同步——按照某种特定顺序访问临界资源,避免线程冲突——内存资源分配

  • 1.临界区(用户态)Critical Section WINDOWS特有
  • 2.互斥量Mutex(内核态)
  • 3.信号量Semaphore(限制访问某些资源的线程数量)
  • 4.事件对象(内核)

  • Linux线程同步方式:——无临界区
    1. 互斥量
    2. 信号量
    3. 事件对象

  • Windows线程同步方式:
    1. 互斥量
    2. 临界区
    3. 信号量
    4. 事件对象

tips:互斥和临界区采用互斥控制,拥有才会执行,执行完释放。

信号量和事件对象采用通知控制,主要用于同步。


特点:

  • A:临界区只能同步本进程内线程,(互斥量、信号量、事件)不可跨进程同步线程。
  • B:
    1. 临界区在用户态下操作,速度快。
    2. 互斥量在内核态下进行锁操作,速度慢。
  • C:Linux下不可以使用临界区

9.线程简介

线程是轻量化的进程,是进程组成的基本单位。不拥有系统所有资源,但是同一进程内的线程共享进程所有资源。

线程组成:线程ID,当前指令指针,寄存器,堆栈。

  • 1.线程ID:用于表示线程
  • 2.寄存器组的值:线程并发运行,切换时需要将原线程寄存器状态保存,用于重新切换时恢复。
  • 3.堆栈:是保证线程独立运行的根本。线程函数可以调用函数,所以线程必须拥有自己的函数堆栈,而不受其他函数影响。位于进程的线程共享堆区内。(heap)
  • 4.错误返回码
  • 5.线程信号屏蔽码
  • 6.线程优先级

进程一般包含多个线程,所有线程间也存在着制约关系,有:就绪,阻塞,运行三种状态


10.进程和线程的区别

  • 1.

    1. 进程是程序的封装,是系统调度的基本单元,用于实现系统的并发性。
    2. 线程则是进程的子任务,是CPU调度的基本单元,用于实现进程的并发性。
  • 2.线程的开销比进程小很多,易于调度,多用可以提高CPU的利用率,提高程序并发性。

  • 3.进程用于自己独立的内存空间,而线程至共享其父进程的内存空间。

  • 4.父进程内的线程间可以直接通信,而进程间通信需要借助操作系统。

有了进程为什么还要线程?

答:1.进程是系统调度的基本单元,而线程是CPU调度的基本单元。

2.在进程的基础上使用线程可以提高程序并发率,CPU的利用率,同时线程作为进程的子任务开销也较小。

3.进程拥有独立的内存空间,无法直接通信。而线程虽然没有独立的内存空间,但是父进程下的子线程都可以共享进程内数据,可以改善程序结构,提高计算效率。



内存管理

1.内存管理

  • A:内存空间的分配与回收
  • B:地址转换——内存物理地址与逻辑地址的转换
  • C:内存空间的管理:虚拟内存和自动覆盖技术,逻辑上扩充内存。
  • D:内存保护:进程间的内存空间互不干扰

2.逻辑地址和物理地址

逻辑地址:程序编译后,每个模块都是从0单元开始编址的,称为模块的逻辑地址。当各个模块链接成一个完整可执行目标时,就成了逻辑地址。

物理地址:内存物理地址的集合,它是地址转换的最终地址。

地址重定位:进程在运行指令和访问数据时都需要物理地址来存取主存。必须将逻辑值转化为物理地址才能正确访问数据,此过程称为地址重定位。


3.内存分配的管理方式(分配程序空间)

A连续分配 / B非连续分配

A连续分配:分配一个连续的内存空间

固定分区分配(产生内部碎片)

示例:

分区A_10MB 分区B_10MB———内部碎片4和 6

进程A_6MB 进程B_4MB

动态分区分配(产生外部碎片)

通过 “紧凑” 技术提高利用率,时间花销大。

B非连续分配:将一个进程分散地装在不相邻的分区中,就无需再凑来节约空间。

img2

*基于分页的存储管理:(无外部碎片,极少数内部碎片) *

将内存分为一个一个相等的小块,再按照块大小拆分进程,放入内存。


img2
*基于分段的存储管理:(分配基本单位为逻辑上的段) *

进程的地址空间按照逻辑分为若干段,每段从0开始编址。以段为单位进行分配,每个段在内存中占据连续空间,但是各个段不相邻。


分页和分段的对比:————页大小固定,段不固定

页是物理单位:为了实现内存的充分利用。是系统管理上的需要,对用户不可见。

段是逻辑单位:为了满足用户的逻辑习惯,以段进行分区包含一个逻辑模块。对用户可见,用户编程需要显示地给出段名。

分页地址空间是一维的。

分段地址空间则是二维的,程序员识别地址时,需要给出段名以及段内地址。

分段比分页更容易实现信息的共享和保护。

img2
段页存储概念:先分段,再分页,内存管理仍采用分页存储管理。

页式存储->提高内存利用效率

段式存储->反映程序的逻辑结构,利于段的共享和信息保护、程序可在执行时再动态链接


虚拟内存管理:

进程的驻留性,进程数据必须一次装进内存中,直至作业完成。这就导致了很多暂时不用的数据占据了内存大量空间。

虚拟内存概念:————内存 / 外寸 / 置换内存

基于局部性原理,将进程的部分数据装入内存,其余部分驻留外存,即可以运行程序。当进程需要外存中的数据时,我们将数据调入内存,置换出不需要的内存。这样就可以提供一个比实际物理内存大的多的存储器,称为虚拟内存。

————需要的数据放入内存,暂时不需要的放置在外存。需要时再置换回内存。

1.虚拟内存的存储管理方式

分页存储管理,分段存储管理,段页存储管理。

使用最多的是分页管理方式,为了支持虚拟内存的管理,增加:1.请求调页功能 2.页面置换功能

需要的硬件支持:1.一定容量内存+外存 2.页表机制 3.终端机构 4.地址变换机构

2.虚拟内存中的页面置换算法

定义:在进程运行过程中,地址映射发现所访问的页不在内存中,将缺失的页从外存中点入内存中。但是当内存无空闲空间,需要移除页给准备进入的页腾位置。

常用的置换算法:

1.OPT——最佳置换算法——置换出接下来最不会被访问的页。理论上的算法,我们不知道哪个页接下来最不会被访问。常常用来作评价算法,因无法实现。

2.FIFO——先进先出置换算法——最早进入的页被置换出内存:当物理内存快增加,可能置换的次数反而变多,因为先进入的页可能被淘汰但是马上又要用。

3.LRU——最久未使用置换算法——将最久未访问的页置换:LRU算法的性能是最好的,但是需要寄存器和硬件的辅助计算支持,LRU是堆栈类算法。

3.虚拟内存的优缺点

优点:

  • 1.提高了逻辑内存大小,内存的利用率
  • 2.每个进程互不干扰,都在自己的虚拟内存空间下

缺点:

  • 1.增加一些内存开销(虚拟内存的管理)
  • 2.增加一些CPU开销(虚拟地址到物理地址的转换、页面置的时间)

4.虚拟内存的特点

  • 多次性:数据分多次装入内存中
  • 置换性:进程运行的同时进行数据,内存外存置换
  • 虚拟性:提高了逻辑内存大小

    5.页面置换中的 颠簸 / 抖动——频繁缺页中断,置换页面——CPU开销增大

定义:页面置换中,当置换出的页,接下来马上又要使用,这样会不断产生缺页中断,这种现象称为颠簸。

需要注意:虚拟内存可以提高逻辑内存,但是页面管理及置换算法不当时,会花费CPU很大的时间去交换页面,而不是执行进程命令,大大降低系统的效率。

6.工作集的概念

定义:某段时间内,进程访问页面的集合。经常被访问的页,我们将其放在工作集内,防止产生抖动现象,因此我们需要选择合适的工作集。

————单独开辟的进程常访问页的内存区域————

作用:选择正确的工作集,可以提高内存的利用率和吞吐效率,减少页面置换的花销。

7.页表寻址——找寻虚拟内存地址对应的物理地址

页表是计算机虚拟内存地址到物理内存地址的映射。页表中的每一项都记录着页的首地址。

首先通过页表的找寻逻辑地址对应的页的首地址,然后通过页的首地址 加上偏移量找到最后的物理地址。
img2

常见问题

问题1.单核计算机多线程程序需要加锁吗

需要,因为程序锁的目的是为了保证线程的同步,防止读取共享数据时发生死锁等线程。单核计算机仍然存在线程同步问题,所以也需要加锁。

问题2.游戏服务器应该为每个用户开辟一个线程还是一个进程,为什么?(互不影响)

开辟进程。同一进程间的线程会相互影响,一个线程死掉会影响其他线程,为了保证用户间互不影响,应该开辟进程。

问题3.请你说一说互斥锁机制,以及互斥锁和读写锁的区别

  • 互斥锁:保证单一对象只有单一线程对其进行操作。
  • 读写锁:分为读锁和写锁。处于读操作时,允许多个线程同时获得读操作,但是同一时刻只允许一个线程获得写操作。同时写锁会阻塞其他操作

不同:

  • 读写锁区分读和写,而互斥锁不区分。
  • 互斥锁只允许一个线程访问该对象。读写锁允许多个读者,但是同一时间只允许一个写着。

问题4.怎样确定当前线程是繁忙还是阻塞

linux下用ps命令查看

问题5.windows消息机制知道吗,请说一说

消息机制是系统将用户的具体操作转化为消息,告诉给进程。有点类似进程通信中的信号。

问题6.说一下僵尸进程和孤儿进程(未回收信息的子进程)

父进程创建子进程,子进程再创建新子进程。子进程的结束和父进程的运行是个异步过程。父进程需要调用wait()等操作取得子进程的终止状态。

  • 孤儿进程:父进程结束了,子进程还在运行。孤儿进程会被进程号为1的进程收养。

  • 僵尸进程:子进程退出时,父进程没有调用wait回收子进程的信息,那么子进程的信息仍保留在系统中,这种进程称为僵尸进程。

  • 危害:僵尸进程是进程必须经过的过程,但是如果父进程未来得及处理退出的子进程,就会变成僵尸进程。这样的话僵尸进程保留的那段信息就不会释放,进程号一直被占用,会导致逐渐没有可用的进程号。

  • 解决:通过kill发出指令,僵尸进程变孤儿进程,再由新的父进程接管消灭。在子进程结束的时候父进程及时wait()取得子进程的终止状态。

问题6.请你来介绍一下5种IO模型

  • 1.阻塞型IO:等待函数返回,不返回不继续,反复检索函数有没有返回
  • 2.非阻塞型IO:每隔一段时间检查IO事件是否就绪,没有仍可以做其他事情
  • 3.信号驱动IO:安装一个信号处理函数,进程不阻塞,收到信号处理IO事件。
  • 4.复用IO:poll,select函数实现复用模型
  • 5.异步IO:可以调用aio_read函数告诉内核描述字缓冲区指针和缓冲区的大小、文件偏移及通知的方式,然后立即返回,当内核将数据拷贝到缓冲区后,再通知应用程序。

问题7.请你说一说异步编程的事件循环

事件循环就是事件是处理器一个一个依次执行的。当一个事件执行完毕,事件循环就会继续等待下一个事件的触发,不断往复。

当单个线程绑定了两个处理器,那么第二个处理器也会等待第一个处理器执行完毕后,才开始执行。

问题8.请你回答一下操作系统为什么要分内核态(root)和用户态(非root)

为了系统的安全性。CPU中的一些指令用错会导致整个系统崩溃。当用户态满足使用要求时尽量使用用户态,避免发生不必要的错误。

问题9.请问怎么实现线程池

  • 1.设置一个生产消费者队列,作为申请线程的临时资源
  • 2.初始化n个线程,并运行,加锁去队列中获取任务
  • 3.无任务,线程阻塞。有任务,队列加锁,条件变量通知其中阻塞的一个线程运行

问题10.说一下C++源文件从文本——>可执行文件 ——经历的过程

  • 1.预处理(产生.i文件):将所以源文件(.cpp)和相关头文件,预处理成一个 .i文件
    1. 将#define删除,并且宏替换
    2. 将#ifdef,#ifndef等不需要的代码删除
    3. 将注释的代码删除
    4. 处理#include预编译指令,将包含的文件插入到该预编译指令的位置,此过程递归进行。
    5. 保留#pragma编译器指令,因为编译器需要。

#ifdef,#ifndef作用:防止头文件重复包含

#include<>和#include” “区别:前者从标准库中找,后者从当前目录开始寻找。

  • 2.编译(产生.s文件):(核心)
    将预处理后的文件,进行一系列的词法分析,语义分析以及优化后产生相应的 汇编代码文件

  • 3.汇编(产生.o/.obj文件):
    汇编实质上是把汇编语言代码 翻译成目标机器指令的过程,即生成目标文件。

  • 4.链接(产生.out/.exe文件):
    链接就是代码中用了别的库,将其和程序进行链接,然后生成可执行文件。按照它们的要求将它们组装起来,链接主要解决的是源代码之间的相互依赖问题,链接的过程包括地址和空间的分配,符号决议,和重定位等这些步骤。

总结

  • 预处理(头文件解析,删除注释,宏替换等)
  • 编译(将预处理后文件,语义分析,优化后生成汇编语言)
  • 汇编(将汇编语言翻译成机器语言,生成目标文件)
  • 链接(链接其他使用了的库,和目标文件结合生成可执行文件)

问题11.静态库 / 动态库的区别

  • 静态库(.a/lib )/动态库(.so/dll )的区别:
  • 两者都由.o目标文件编译生成。可以理解为目标文件的一个集合。
  • 静态库在链接过程中,会将静态库和目标文件(.o)一起打包到可执行文件中。删除后,程序仍可以执行。
  • 动态库并不会打包到可执行文件中,只有在程序被执行时才会被载入,避免了浪费资源。
文章作者: Inter
文章链接: https://zuizichuan.cn/2020/07/13/inter2/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Zichuan365' Blog