OS基础知识


进程和线程有什么区别?

进程是系统进行资源分配和调度的基本单位,线程是cpu调度和分配的基本单位。

线程依赖于进程而存在,一个进程至少有一个线程。进程有自己独立的地址空间,线程之间共享进程的地址空间。

进程是拥有操作系统资源的独立单位,而线程自己基本不拥有系统资源,仅仅拥有一些基本资源,例如程序计数器,一组寄存器和栈,和其他线程共享所属进程的系统资源,cpu,io,内存等等

进程切换时,涉及到整个当前进程的cpu环境的保存和新被调度的进程的cpu环境设置,而线程切换时只需保存和设置少量的cpu寄存器的内容,不涉及存储器的管理方面的操作,所以进程切换的开销远大于线程切换的开销

线程之间通信的方式更方便:可以通过共享同一进程下全局变量等数据进行通信
进程间通信方式:通过进程间通信IPC进行

多线程程序中一个线程崩溃会导致整个程序崩溃,多进程程序中一个进程崩溃不会导致其他进程崩溃,因为进程有自己独立的内存地址空间,更加健壮。

同一进程中的线程可以共享哪些数据?

进程代码段,进程的公有数据例如全局变量,静态变量等等。进程打开的文件描述符,进程当前目录,进程ID,进程组ID

线程独占哪些资源?

线程ID。一组寄存器和栈。线程产生的错误返回码。

进程间通信有哪些方式?

管道:半双工,如果需要双向通信需要两个管道。写进程在管道的缓冲区末尾写入,读进程在管道的缓冲区头部读出。

共享内存,消息队列,信号量

信号量:pv操作,p操作信号量减一,v操作信号量加一。检测信号量是否小于零,小于零则进行阻塞,大于零则从等待队列中唤醒一个进程进入就绪状态。

进程同步问题

管程将共享变量和对共享变量的操作封装起来,形成一个具有一定接口的功能模块,当一个进程需要对共享变量进行操作的时候,必须通过管程的某个过程才能访问管程中的资源,进程只能互斥的使用,使用完之后必须释放管程并唤醒在入口等待队列中的进程。

MESA管程:java中使用的管程模型就是MESA管程,他将HOARE中的signal换成了notify,进行通知而不是立刻交换管程的使用权,在合适的时候条件队列中的首位进程可以进入,进入前使用while检查条件是否合适。
优点:没有额外进程切换。

生产者-消费者:使用一个缓冲区存放数据,不为满时生产者可以写入,不为空时消费者可以读出。

初始状态,full为0,empty为n
semaphore full = 0, empty = n, mutex = 1;
void producer(){
    p(mutex);
    p(empty);
    生产
        v(full);
    v(mutex);
}
void consumer(){
    p(mutex)
        p(full)
        消费
        v(empty)
        v(mutext)
}

哲学家就餐:五个哲学家五个筷子,哲学家要么思考要么吃饭。如何避免死锁。

semaphore int[] chopstick, mutex;
int[] state;
void philosopher(int i){
    think()
        take_c()
        eat()
        put_c()
}
void take_c(){
    p(mutext)
        if((chopstick[i] & chopstick[i+1]) == 1) //左右两个筷子都在
            chopstick[i] = 0 
            chopstick[i+1]) = 0
            state[i] = EATING
       v(mutext)
}
void put_c(){
    p(mutext)
        if(state[i] == EATING)
            chopstick[i] = 1 
            chopstick[i+1]) = 1
            state[i] == THANKING
       v(mutext)
}
临界区的概念?

本质就是一段代码块,在这个代码块中会有多个进程访问共享的资源和变量,但各个进程直接只能互斥的访问。

同步与互斥的概念?

同步:各个进程间按照顺序执行

互斥:多个进程在同一时刻只有一个进程进入临界区

并发、并行、异步的区别?

并发:一个时间段内有多个程序同时运行,但在某一时刻只有一个程序在真正运行,宏观上是通过不断进行切换进程实现的。

并行:在某一时刻,有多个程序在真正同时运行

异步:异步是指各个程序之间并不一定按照一定的顺序先后执行,可能通过并发,并行的手段同时执行多个任务

进程有哪几种状态?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PwPdzUou-1633588896366)(D:\包\New folder\test\Waking-Up-master_v_images\20191202090217863_1873.png)]

就绪:有权限无时间片
运行:有权限有时间片
阻塞:进程等待某种条件,只有条件满足后才能继续执行

进程调度策略有哪些?

先来先服务:非抢占式

最高响应比优先:1+等待时间/处理时间,很好的平衡了长短进程,非抢占式

时间片轮转;就绪进程按照先来先服务原则排成一个队列,用完时间片的进程排到最后,抢占式,无饥饿问题

优先级:为每个进程分配一个优先级,按照优先级的顺序执行,为了避免饥饿问题可以将等待时间久的进程提升优先级。

多级反馈队列:按照优先级递减,时间片递增,设置多个就绪队列,只有当高优先级的队列中没有待执行任务时,才从低优先级队列中取出任务进行执行。如果高优先级队列中的一个进程用完了时间片还没有被执行完,那么就将它移入下一个队列。抢占式。

什么叫优先级反转?如何解决?

当一个高优先级任务通过信号量机制访问共享资源时,信号量已经被一些低优先级任务占有,导致高优先级任务被低优先级任务阻塞,实时性无法得到保证。

1.优先级天花版,当某任务申请资源时把这个任务优先级提高到所有可以访问这个资源的任务当中的最高级。
2.优先级继承:高级别任务访问资源时,若该资源正在被低级别任务访问,则把低级别任务的级别调整到和高级别任务相同。

什么是僵尸进程?

一个子进程结束后他的父进程并没有等待他(wait或者waitpid),那么这个子进程将成为僵尸进程,僵尸进程是死亡的进程,但并没有被真正销毁。有如下特点:放弃了几乎所有内存空间,没有可执行代码,不可被调度,仅在进程表中保留一个位置,可能会一只保留直到系统重启。

危害:占用进程号,占用内存

什么是孤儿进程?

一个进程的父进程已经结束,但子进程依然在运行,那么这些子进程将成为孤儿进程,孤儿进程会被lnit接管,lnit会在孤儿进程结束时完成状态收集工作

线程同步有哪些方式?

互斥锁:mutex是内核对象,拥有互斥锁的进程才能访问互斥资源,互斥锁只有一个,线程在结束访问互斥资源后必须释放互斥锁。

信号量:信号量是内核对象,允许同一时刻多个线程访问同一个资源,但要控制最大线程数量。保存了最大资源计数和当前可用资源计数。只要当前资源计数大于零,就可以发出信号量信号,如果为0,则将线程放入一个等待队列中等待。

事件:EVENT,一个线程在处理完任务后主动唤醒另一个线程执行任务。手动重置事件:手动重置事件被设置为激发态之后,会唤醒所有等待线程,并且一直保持激发状态,直到程序重新把它设置为未激发状态。自动重置事件:自动重置事件被设置为激发态后会唤醒一个等待中的线程,然后自动进入未激发状态。

临界区:任意时刻只允许一个线程对临界资源进行访问,拥有临界区对象的线程可以访问该临界资源,其他试图访问该资源的线程将被挂起,直到临界区对象被释放。

互斥量和临界区有什么区别?

互斥量是可以命名的,可以用于不同进程之间的同步,临界区只能用于同一进程中线程的同步。创建互斥量需要消耗资源,临界区的优势是速度快,省资源。

什么是协程?

由用户完全控制的,用户态的轻量级线程,拥有自己的寄存器和上下文栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,切换回来的时候恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文切换非常快。

协程多与线程进行比较?

线程可以拥有多个协程,进程可以单独拥有多个协程
线程进程都是同步机制,而协程是异步机制
协程能保留上一次调用时的状态,每次过程重入时,相当于进入上一次调用状态

进程的异常控制流:陷阱、中断、异常和信号

陷阱是有意造成的异常,是指令执行的结果。主要作用是实现系统调用,进程可以执行syscall n 指令向内核请求服务,中断当前控制流并陷入到内核态,执行完成后会将结果返回给进程,同时退回到用户态,继续执行下一条指令。

中断由处理器外部硬件产生,不是执行某条指令的结果,也无法预测发生时机。中断独立于当前运行的程序,所以中断是异步事件,中断包括IO设备发出的IO中断,定时器引发的时钟中断,调试程序设置断点等引起调试中断。

异常是一种错误情况,是执行当前指令的结果,可被错误处理程序修正也有可能直接终止应用程序。异常是同步的,特指因为执行当前指令而产生的错误情况。如除法异常缺页异常等。

信号是更高层的软件形式的异常,同样会中断进程的控制流,可由进程进行处理,一个信号代表一个消息,信号作用是通知进程发生了某种系统事件。

什么是IO多路复用?怎么实现?

IO多路复用:单个进程或者线程就可以同时处理多个IO请求

实现原理:用户将想要监视的文件描述符添加到select epoll函数中,由内核监视,函数阻塞,一旦有文件描述符就绪(读就绪或者写就绪),或者超时,函数就会返回,然后进程可以进行相应的读写操作。

select模式:将文件描述符放入一个集合中,调用select时,将该集合从用户空间拷贝到内核空间。内核根据就绪状态修改集合内容,采用水平触发机制,select函数返回后,需要通过遍历(轮询)集合找到就绪的文件描述符。文件描述符数量增加时,效率会线性下降。

epoll:用户和内核共享内存,避免不断复制的问题,支持连接数上限高,文件描述符就绪时采用回调机制,避免轮询。(回调函数将就绪的文件描述符添加到一个链表中,执行epoll_wait时,返回这个链表),支持水平触发和边缘触发,采用边缘触发时,只有活跃的描述符才会触发回调函数。

两者主要区别:
支持最大连接数不同
文件描述符的传递方式不同(是否复制)
水平触发和边缘触发
查询就绪描述符时,轮询还是回调

select 和 epoll的使用场景:
连接数多,且大多数连接都不活跃时,epoll效率高。连接数少,且都比较活跃的情况下,由于epoll需要很多回调,因此性能可能低于其他两者。

文件描述符是什么?
文件描述符形式上是一个非负整数,实际上是一个索引值,指向内核为每一个进程维护的,该进程打开或新建的记录表,程序打开或新建一个文件时,内核向进程返回一个文件描述符。

内核通过文件描述符访问文件,文件描述符指向一个文件。

什么是水平触发?什么是边缘触发?

水平触发:如果文件描述符已经就绪,就可以非阻塞的执行IO操作了,此时会触发通知,允许在任意时刻重复检测IO状态,没有必要每次描述符就绪后尽可能多的执行IO。(当被监控的文件描述符上有可读写的事件发生时,会通知用户去读写,如果用户一读写没取完数据,会一直通知用户,如果这个描述符是用户不关心的,他每次都返回通知用户,会导致用户对关心的描述符处理效率变低)

边缘触发:如果文件描述符自上次状态改变之后有新的IO到达,此时会触发通知,在收到一个IO事件通知后要尽可能多的执行IO操作,因为如果在一次通知中没有执行完IO操作,就需要等待下一次新的IO活动到来时才能获取到就绪的描述符。(有可读写事件发生时会通知用户读写,但只会通知用户进程一次,需要一次把内容读取完,比水平触发效率高,如果没读完再次请求时不会返回,要等下一次新数据到来才返回)

有哪些常见的IO模型?

同步阻塞IO:用户线程发起IO读写之后,线程阻塞,直到可以开始处理数据

同步非阻塞IO:用户线程发起IO之后立刻返回,如果没有就绪的数据,就不算发起IO请求直到数据就绪,不算重复消耗大量资源

IO多路复用

异步IO:用户线程发起IO请求之后,继续执行,由内核读取数据并放在用户指定缓冲区内,IO完成之后通知用户线程使用

什么是用户态和内核态?

为了限制不同程序的访问能力,防止一些程序访问敏感数据或指令,cpu划分了用户态和内核态两个不同的权限等级。

用户态:受限地访问内存,不允许访问外围设备,没有占用cpu能力,cpu资源可被其他程序获取
内核态:内核态可以访问内存所有数据以及外围设备,也可以进行程序切换

所有用户程序都运行在用户态,有时需要进行一些内核态的操作,从硬盘或者键盘读取数据,就需要进行系统调用,使用陷阱指令,切换到内核态,执行相应服务,再切换回用户态并返回调用结果。

为什么要分用户态和内核态?

安全性,保护系统资源。封装性,用户程序无需实现底层代码。利于调度,多个用户程序等待键盘输入时交给操作系统调度更方便。

如何从用户态切换到内核态?

系统调用:读取命令行输入,本质通过中断实现
用户程序发生异常:如缺页异常
外围设备中断:外围设备完成用户请求操作后向cpu发送中断信号,这时cpu会转去处理对应中断处理程序。

什么是死锁?饥饿?

死锁:两个及以上进程之间,由于竞争资源产生,导致进程无限等待,可以检测出来
饥饿:由于资源策略分配不公平引起,不一定处于等待状态,可能处于忙等或就绪态

死锁产生的必要条件?

互斥,占有并等待,非抢占(已分配的资源不能被强占只能自愿释放),循环等待

死锁有哪些处理方法?

死锁预防:破坏死锁形成的四个必要条件

死锁避免:动态监测资源分配状态,只有确保系统处于安全状态时,才进行资源分配。安全状态是指即使所有进程突然请求需要的所有资源,也能存在某种对进程的资源分配顺序,使得每一个进程运行完毕。(银行家算法)

死锁解除:
强占进程资源,设置进程还原点在需要时回滚进程使其资源释放资源,杀死进程。

分页和分段有什么区别?

页式存储:用户空间划分为大小相等的部分称为页,内存空间划分为同样大小的区域称为页框。分配时以页为单位按照进程需要的页数分配,逻辑相邻的页在物理上不一定相邻。

段式存储:用户进程地址空间按照自身逻辑关系划分为若干段(代码段,数据段,堆栈段),内存空间被动态划分为长度不同的区域,分配时以段为单位,每段在内存中占据连续空间,各段可以不相邻。

段页式存储:用户进程先按段划分,段内再按页划分,内存划分和分配页。

分段和分页的区别:
目的不同:分页目的是管理内存,分段目的是满足用户需要,使得程序和数据可以被逻辑上划分为独立的地址空间。
大小不同:段大小不固定,由其所完成的功能决定。页大小固定,由系统决定。
地址空间维度不同:分段是二维地址空间(段号+段内偏移),分页是一维地址空间(每个进程一个页表/多级页表,通过一个逻辑地址就能找到对应的物理地址)
分段便于信息的保护和共享,分页的共享受到限制。
碎片:分段没有碎片,但会产生外部碎片,分页没有外部碎片,但一页填不满时会产生内部碎片

什么是虚拟内存?

每个程序都有自己的地址空间,地址空间被分成大小相等的页,这些页被映射到物理内存,但不需要所有的页都在物理内存之中。程序引用到不在物理内存中的页时,操作系统将缺失的部分装入物理内存,这样对程序来说逻辑内存上似乎有很大的空间,但实际上有一部分存储在磁盘上。

虚拟内存让程序可以获得更多可用内存,虚拟内存有多种实现方式,页表多级页表,缺页中断,页面淘汰算法等

如何进行地址空间到物理内存的映射?

内存管理单元:管理着逻辑地址和物理地址的转换。
页表:存储页(逻辑地址)和页框(物理地址)的映射关系的表。包含有效位(是否在磁盘),访问位(是否被访问过),修改位(内存是否被修改过),保护位(只读还是可写)。
逻辑地址:页号+页内偏移
每个进程一个页表放在内存,页表起始地址在进程寄存器中(PCB/寄存器中)

有哪些页面置换算法?

最佳页面置换:置换以后不需要或者最远将来才需要的页面
先进先出:置换内存中驻留时间最长的页面,缺点:可能置换出经常被访问的页面使缺页率升高
第二次机会算法scr:按先进先出选择一个页面,如果访问位为1,给第二次机会并将访问位置零。
**时钟算法:**scr需要将页面从链表头移动到链表尾,时钟算法使用环形链表,再用一个指针指向最老页面,避免移动页面开销
最近未使用算法:检查访问位R,修改位M,优先置换R=M=0,其次是(R=0,M=1)
**最近最少使用算法LRU:**置换出未使用时间最长的一页,实现方式是维护时间戳。或者维护一个所有页面的链表,页面被访问到时将该页面移动到链表表头,就能保证链表表尾页面时最近最久未被使用的。

局部性原理:
空间:内存中被访问的页面周围的页面也很可能被访问
时间:最近被访问的页面不久的将来还会被访问

颠簸:
本质上是频繁的页面调度行为,内存里所有的页都在使用,置换一个页,又立刻再次需要这个页,所以不断产生缺页中断,导致系统效率下降。称为颠簸。

修改页面置换算法,降低进程数量,增加物理内存容量。

缓冲区溢出问题

缓冲区溢出是什么?
数据被添加到分配给该缓冲区的内存块之外。

防范缓冲区攻击的方法:随机化(随机分配栈空间+将代码段数据段栈堆等加载到内存不同区域),栈保护(栈帧局部变量和栈状态间存储一个随机产生的特殊值,检测该值是否变化),限制可执行代码区域(内存页访问形式有三种:可读,可写,可执行,只有编译器产生那部分代码的内存才可执行,其他只允许读和写)。

磁盘调度

磁头:找到对应的盘面。磁道:一个盘面上的同心圆环,寻道时间。扇区:旋转时间。
为了减少寻道时间的调度算法。

先来先服务:
最短寻道时间优先:
电梯算法:电梯总是保持一个方向运行,直到该方向没有请求为止,然后改变运行方向。

文件系统挂载

linux中一切皆文件,包括硬件设备也是文件,所有文件放置在/ 为根目录的树形目录文件结构中,任何设备也有一套自己的文件目录系统。

在使用任何硬件设备时,硬件设备本身有一套文件系统,linux本身也有一套文件系统,需要把这两个系统合二为一才我们才能在linux中使用硬件设备的文件系统,这个过程就是挂载,感觉是建立硬件设备系统到linux文件系统的映射。就是将设备文件的根目录映射到linux根目录/下的某一个目录(最好为空)。挂载到根目录下的硬件设备就成为linux根目录下的一个子目录,访问这个子目录就是访问硬件的文件系统。

在linux中使用任何硬件设备都必须将硬件设备和已有的文件系统进行挂载。

cpu缓存

程序优化:CPU缓存基础知识:https://zhuanlan.zhihu.com/p/80672073
为什么cpu需要用到缓存:http://www.dnpz.net/diannaoyingjian/diannaoyingjianzhishi/2805.html

我的理解是这样的,一般来说cpu读取缓存中数据很快,读取内存中数据很慢,此时如果cpu要使用一个内存中的数据,如果直接从内存中读取,则必须等待很久,和处理这个数据需要的时间相比太久了,所以先将数据从内存读取到缓存中,此时cpu可以干别的事情,等到内存数据完全读取到缓存中后,cpu再从缓存读取该数据,由于缓存和cpu速度接近,可以很快的读到cpu中而不必过多等待,节省了cpu对数据io的时间,提高cpu利用率。

在查找需要使用的数据时,现在缓存里查找,如果有则直接使用,没有再去内存中找,不然每次都去内存中找会浪费大量时间。

回调是什么

有些函数要求传入一个函数作为他的参数,好在合适的时候进行调用,这个被传入的,后又被调用的函数就称为回调函数。
一个观点是:回调函数通常和应用处于同一抽象层(传入什么样的回调函数是在应用级别决定的),回调就形成了一个高层调用底层,底层在返回来调用高层的过程。这应该是回调最早的应用之处。

更广义的,把底层函数改为中间函数,任何两个进程之间想获得类似上面的灵活性,都可以利用回调。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值