实习秋招操作系统知识点总结

实习/秋招时按自己需求总结的知识点,内容并不十分详细,建议选择性阅读。

进程

进程是系统进行资源分配和调度的基本单位,由程序、数据和进程控制块PCB组成。PCB用于记录进程信息,如程序计数器,记录进程所在地址;状态,记录其状态

进程状态
  • 创建。初始化进程控制块,分配内存;

  • 就绪。已完成除CPU资源以外的所有资源的分配,一旦获得处理器资源即可运行;

  • 执行。获得CPU资源并执行

  • 阻塞。因某种事件而无法执行,放弃CPU资源而挂起。如IO等待,缓存得不到满足,等待信号灯

  • 死亡。调用exit退出。释放资源

  • 只有执行和就绪会相关转换,其余都是单向的,进程执行完时间片后插入到进程队列进入就绪状态,等待下一次被调用;获得时间片后进入执行状态

  • 进程的创建和销毁实际上都是对PCB的释放和销毁。

进程创建和释放的优化方案

Linux系统采用slab分配器来快速分配同一类型的内存区,可降低进程的创建和释放所带来的开销。
内核在创建新进程时,要为固定大小的表(如进程描述符,文件打开等)分配内存,当进程结束后,就要释放内存
在没有slab分配器时,内核把时间浪费在反复分配和回收包含同一内存区的页框上;而slab分配器将这些页框放在高速缓存中,从而可以快速重利用,降低分配的开销

线程

线程是在进程中活动的对象
线程是CPU调度的基本单位,在linux中相当于轻量级进程,两者区别在于:
1.资源。进程是资源分配和调度的基本单位,线程不拥有资源,线程可以访问进程的资源;
2.调度。同一进程中的多个线程切换不涉及进程切换,从一个进程中的线程切换到另一个进程的切换则需要进程切换;
3.系统开销。创建和销毁进程时,系统都要分配和回收资源,进程切换时,涉及当前执行进程CPU环境的保存及新调度进程CPU的设置,而线程切换只需保存少量寄存器的切换,开销很小
4.通信。线程间可以通过读写同一进程中的数据进行通信,但进程间通信需借助IPC。

内核线程

是指在内核空间运行的线程,用于执行内核中的某些任务,内核线程不拥有地址空间(mm_struct为NULL),不会切换到用户态,可以被抢占,内核线程只会被其他内核线程创建
内核线程通常在创建之时就一直执行,直到linux系统重启

init进程

linux在启动时第一个运行的进程,其pid为1,该进程用于初始化系统,启动各种服务和登陆进程

僵尸进程

子进程在父进程结束之前结束,完成了生命周期但停留在进程表中未被删除。

产生过程

子进程完成执行,内核发送一个SIGCHLD信号给父进程,父进程调用wait命令来读取子进程的退出状态,并将子进程从进程表中移除;若父进程未捕捉到SIGCHLD信号,则父进程无法阐述该子进程,仍停留在进程表中,成为僵尸进程
僵尸进程只会在进程表中占用一个位置,其余资源几乎已完全释放,因此也不必过于担心

父进程为什么会读取不到exit信号?

未捕获SIGCHLD信号

怎么避免僵尸进程

1.改写父进程,写一个SIGCHLD信号捕捉函数,在函数中调用wait;
2.调用fork两次
3.用waitpid等待子进程返回

怎么处理僵尸进程

删除父进程,此时,其子进程会成为孤儿进程,init进程会接管所有的孤儿进程并清除之

ps -aux | grep Z # 查找僵尸进程
kill -s SIGCHLD pid # 此处pid为其父进程id,为父进程显示指定SIGCHLD信号使其能调用wait

使用ps -aux | grep Z命令查找僵尸进程

多进程和多线程的使用场景
  • CPU密集型,涉及CPU资源的频繁切换,用多线程,如图形图像处理;
  • IO密集型,需要进行大量IO的场合,用多线程
  • 多机多核,多进程
协程

https://www.zhihu.com/search?type=content&q=%E5%8D%8F%E7%A8%8B%E5%92%8C%E7%BA%BF%E7%A8%8B%E7%9A%84%E5%8C%BA%E5%88%AB
进程和线程的切换由内核控制,协程由程序自己控制,因此避免了进程/线程中上下文切换的开销,非常高效
常用yield关键字

  • 适用于IO密集型
  • 高性能计算
协程的优势
  • 有自己的状态寄存器和栈,协程上下文切换更小
  • 一个CPU可支持上万个协程,高并发
  • 实现在用户态
  • 无需原子操作锁定及同步的开销
    https://www.jianshu.com/p/2782f8c49b2a

我在以C#为脚本写Unity时接触过Coroutine,主要用于游戏中:
1)角色状态切换/关卡切换的延时;如:在游戏中开启新关卡,需加载时间,这个加载交由协程处理,每一帧都扫描判断是否完成,在主线程中进行角色动作的变换/对白
2)下载网络资源时等等;如:下载资源时,游戏角色能继续处理别的事物,或者循环播放某些画面,直到下载资源完成

void DoSomething()
{
    // do something
    yield return new WWW;
    // do something
}
void Start()
{
    StartCoroutine("DoSomething");
    
}
进程调度
批处理系统

用户操作较少,需保证吞吐量和周转时间
1.先来先服务(FCFS)
非抢占式,按请求的顺序服务。对长时间执行的任务更好
2.短作业优先(SJF)
非抢占式,占用时间片更短的短作业优先处理,长时间作业可能会饿死
3.最短剩余时间优先(SRTF)
抢占式,SJF的改进。新作业到来时会与当前作业的剩余时间做比较,时间短者优先

交互式系统

有大量的用户交互操作,需保证快速响应
1.时间片轮转
将所有就绪进程按FCFS原则排成队列,队头的进程执行完时间片后插入队尾,如此轮转循环

  • 优点,每个进程都能公平保证运转一定时间
  • 缺点,进程切换是个开销很大的操作,时间片过短会频繁切换影响性能,时间片过长则实时性难以保证

2.优先级调度
为每一个进程设计一个优先级,优先级高者在前,为防止低优先级者无法被调用,可将其设置为优先级随等待时间增长而增加
FCFS和SJF均可视为一种优先级调度,此类为静态优先级
动态优先级调度中,进程每执行一次,优先级则下降一级,等待时间长者优先级提升
3.多级反馈队列
设置多个优先级队列,每个队列优先级不同(第一个最高),时间片也不同(1,2,4,8…),在当前队列执行完后插入到下一队列继续排队等待

进程同步
临界区

对临界资源进行访问的代码被称为临界区。

进程间通信IPC

1.管道。通过pipe函数创建,只支持半双工,只能在父子或兄弟进程间使用
2.FIFO,命名管道。去除了管道中在父子间通信的限制,常用于客户端-服务端之间传递数据
3.消息队列。独立于读写进程,避免FIFO同步管道中同时打开或关闭时的阻塞问题,可以有选择的接收消息。
4.共享内存。允许多个进程共享一块给定的存储区,速度最快,需要使用信号量来同步对共享存储的访问
5.套接字。用于不同机器间的通信

共享内存的实现

需要同步机制,如信号量/互斥量

  • Windows下
    调用CreateFileMapping创建内存映射文件对象,调用MapViewOfFile将内存映射到进程地址空间;其他进程要使用时,调用OpenFileMapping取得内存的对象句柄,调用MapViewOfFile将内存映射到自己的进程地址空间,从而两者实现共享
  • Linux下
    1.用mmap实现,用munmap解除映射
    父子进程采用匿名映射共享内存
    2.系统V
    3.Posix
死锁
死锁产生的条件
  • 一个资源只能被一个进程互斥访问
  • 一个进程已拥有资源,还能继续申请资源
  • 进程申请资源得不到满足,自己的资源不会被抢占
  • 多个进程相互等待请求的资源,陷入死循环
避免死锁的方法

从打破上述四个条件来考虑

  • 进程申请的资源得不到满足,则释放已有资源
  • 预先分配所有资源
  • 给请求的资源分配序号,只能按序号分配

linux中的分段和分页

https://www.cnblogs.com/thrillerz/p/6031561.html

分段

针对程序。将程序所需的内存大小的虚拟地址空间映射到物理地址空间
分段可由程序控制,地址二维,大小不同,可动态增长,主要是为了将程序划分为逻辑上独立的地址空间
分页由系统决定,地址一维,大小固定,分页主要用于实现虚拟内存,从而获得更大的地址空间

分页

针对内存。操作系统将内存地址空间划分为若干固定大小的页,每一页的标准大小为4kb(也可为4MB或2MB,采用4kb是因为1)传输小块数据更高效;2)缺页异常时更易处理),在进行内存分配时,都已页为单位,此外,linux还设计了多级页表,以提升缓存命中。该机制通过MMU(内存管理单元)将虚拟地址映射到不连续的物理地址。当程序将虚拟地址映射到物理地址时,发现该地址还未分配,就会产生缺页中断,并陷入到内核态来未进程的虚拟地址分配物理地址

Linux系统将内存划分为用于硬件的保留区,供内核使用的保留区,以及普通区,通常用户只会使用普通区,内存页的分配也是在普通区完成

页面置换算法

https://github.com/CyC2018/CS-Notes/blob/master/notes/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%20-%20%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86.md#%E8%99%9A%E6%8B%9F%E5%86%85%E5%AD%98

若访问的页面不在内存中,则会产生缺页中断陷入内核,将该页调入内存中;若内存已满,则需要将内存中的某个页调出至磁盘以腾出空间

  • OPT,选择最久未被使用的页面替换,仅理论上可行,因为无法确定哪个页面最久未被使用

  • LRU最近最久未被使用算法。采用链表实现,每次访问时将页面移入表头,删除时剔除表尾

    4,7,0,7,1,0,1,2,1,2,6
    在这里插入图片描述

  • 先进先出,可能会将经常访问的页面换出

  • 第二次机会算法,类似于循环链表

内存分配

https://www.cnblogs.com/wangliangblog/p/9109384.html
频繁请求大小不同的连续页框,必然会在两个连续页表之间产生大量小块的空闲区域,为解决该问题,通常由两种算法:

  • 利用分页单元把非连续的页框映射到连续的地址空间
  • 记录现存的空闲连续页的使用方法,避免因小块内存的分配而切割了大的内存卡

Linux系统采用第二种,原因在于:

  • 系统有时必须要用连续的内存块,如DMA
  • 频繁的修改页表会增加访问内存的次数

https://blog.csdn.net/qq_26768741/article/details/54375524 进程描述符mm_struct

伙伴系统算法(buddy)

Linux系统将空闲页框分为11个块链表,每个链表大小为1,2,4,…,1024,分配内存的过程如下:

假设用户请求256个页框大小的内存,就会从256个页框的链表中查找,若不满足,则从含512个页框的链表中查找;若满足,则分配,并将其一分为二,一块用于满足请求,另一块插入到那个256个页框的链表中;若仍不满足,则从1024个页框的链表中查找,以此类推。即每次从刚好满足要求的临近链表(伙伴)中查找

slab算法

伙伴系统算法中的最小分配单元为1个页表大小,标准为4KB,因此在分配小内存(如只有几十字节)的情况下效率并不高,由于某个页表内的内存并没有完全使用,因此会产生内存碎片问题
slab主要是用于解决上述问题的---->使用slab高速缓存,为频繁使用的物理结构分配内存
slab还可以将内存对齐
kmalloc分配连续内存空间
vmalloc分配非连续内存区域

提问

  • 用户态和内核态的区别?
    系统执行一个程序时,通常是位于用户态的,当用户有以下三种之一时会陷入内核态:
    1.系统调用。如文件读写,网络通信等操作。
    2.异常。如除0.
    3.外围设备的中断。如IO
  • 系统调用
    程序通过系统调用陷入内核,内核处理完毕后将结果返回给系统,是切换到内核态的唯一合法手段
    其作用在于:
    1.提供了用户访问内核的接口
    2.保证了安全性和可靠性
    3.将底层设备的差异隔离开来,使得用户可以专注逻辑

DMA

直接内存存取。DMA指外部设备不通过CPU而直接与系统内存交换数据的技术,该方式使得系统可以处理不同速度的外围设备,该过程通过DMA控制器完成。
存取时,DMA会发出HOLD命令接管CPU,当CPU发出允许信号后,DMAC接管对总线(总线有地址总线AB,数据总线DB和控制总线CB)的控制,完成数据传输,再使CPU恢复状态。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值