面试题解

您所在的位置:网站首页 操作系统分配方法 面试题解

面试题解

2024-07-09 11:20| 来源: 网络整理| 查看: 265

操作系统 (1)进程和线程的区别

进程是执行着的应用程序,而线程是进程内部的一个执行序列。一个进程可以有多个线程。线程又叫做轻量级进程

**根本区别:**进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位。( 线程是可由CPU直接运行的实体)内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。**开销:**CPU切换一个线程比切换进程开销小,创建一个线程比进程开销小**所处环境:**在操作系统中能同时运行多个进程(程序);而在同一个进程中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)。通信:线程之间通信更方便,同一个进程下,线程共享全局变量,静态变量等数据,进程之间的通信需要以通信的方式(IPC)进行;(但多线程程序处理好同步与互斥是个难点)包含关系:一个进程最少由一条线程组成。多个线程共享CPU可以实现并发运行 【问题0】操作系统为进程分配了哪些资源

包括用于存放程序正文、数据的磁盘和内存地址空间,以及在运行时所需要的I/O设备,已打开的文件,信号量等

所谓系统分配资源就是包括内存、I/O和CPU等,那程序要用多少资源就分多少给它,不够分就会崩溃~

【问题】操作系统为什么要进行线程调度,是如何进行的呢

引入线程模型,目的就是为了让进程可以同时做多件事(线程是进程的分身)。此外,引入线程模型后,cpu的最小执行单位就变成了线程。

【问题1】如何杀死一个进程

命令行:kill -9 pid杀死进程

“kill -9 -1”,会杀掉所有进程,请谨慎使用!

【问题2】进程的组成

进程 = 程序 + PCB

程序 = 代码 (指令)+ 数据

进程控制块(Process Control Block,PCB)

描述进程状态、资源、和与相关进程关系的数据结构。

PCB是进程的标志

创建进程时创建PCB;进程撤销后PCB同时撤销。

image-20210410175736283 【问题3】为什么要使用多线程

1、避免阻塞(异步调用)

2、避免CPU空转

3、提升性能

花销小,切换快:启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间。而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。方便的通信机制:对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时且不方便。同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,快捷且方便。耗时的操作使用线程,提高应用程序的响应速度。多CPU系统中,使用线程提高CPU利用率。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。 【问题4】线程过多会怎么样?怎么处理线程过多? 内存空间性能内存同步线程阻塞(尤其是存在锁竞争的情况下)

首先线程作为操作系统的最小调度单位也是要占用内存空间的,其次线程调度及上下文切换也会消耗性能。一般线程数为cpu个数*2+1较好,线程太多会占用内存,频繁的线程上下文切换也会导致效率降低。

内存同步问题。线程阻塞,尤其是存在锁竞争的情况下。

1.如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换.

2.更多的线程需要更多的内存空间

3.线程中止需要考虑对程序运行的影响.

所以减少锁竞争的主要方法是:减少锁的持有时间、降低锁的请求频次、或者使用带有协调机制的独占锁替代,因为这些机制允许更高的并发性。

减少锁竞争手段:第一个是缩小锁的范围:将与锁无关代码移除同步代码块,尤其是那些可能发生阻塞的操作比如I/O;第二个是减少锁的粒度:使用多个相互独立锁管理独立的状态变量,改变某个变量只用获取对应变量锁,而不用获取整体锁,其他线程仍然能使用其他变量。但是使用锁越多,那么发生死锁的风险也就越高。第三个是锁分段:比如ConcurrentHashMap底层的链表数组,对数组中每一个数组元素进行加锁,数组长度是多少就有多少个锁,也就最大支持多少并发。不过在对数组扩张的时候就会更加复杂;第四个是避免热点域:当一个操作要访问多个变量时,锁的粒度就很难减少了,一种解决方法是将这多个变量的计数结果缓存起来,都会引入一些“热点域”,这些热点域往往会限制可伸缩性。

【问题5】减少锁竞争手段:

1)通过使用synchronized代码块儿代替在方法上添加synchronized来保护共享状态的方法,减小锁的范围,减少线程持有锁的时间。:将与锁无关代码移除同步代码块,尤其是那些可能发生阻塞的操作比如I/O

2)锁的分解,例如一个类有两个共享状态,一个是人,一个是钱,分别提供两个锁,分别对应这两个共享状态,那么即可减少持有锁的频率。

3)锁的分解的进一步扩展那就是锁的分段,例如共享状态人是使用HashTable保存那么程序性能因为经常持有锁二成为性能瓶颈,使用ConcurrenthHashMap来代替Hashtable,因为ConcurrentHashMap使用的是默认16个锁类分别管理整个map的1/16的元素,那么每个线程在写入程序的时候,不需要持有整个map的锁,减少了持有锁的频率。

4)避免热点域,例如ConcurrentHashMap的size,用户保存集合的元素个数,单数看似可以O(1)操作的直接获取的操作,却因为是没有个设计修改元素个数的操作都会访问这个属性成为并发的另一个伸缩性问题,ConcurrrentHashMap通过每一个Segment维护一个count,这样在需要的时候再汇总,避免频繁访问size的问题。

5)使用ReentranReadWriteLock。

6)合理使用原理变量类。

7)合理使用volatile。

【问题5】线程间通信

线程间的通信主要用于线程间同步,而非数据传输。

等待唤醒机制:(wait()、notify())就是在一个线程进行了规定操作后,就进入等待状态(wait), 等待其他线程执行完他们的指定代码过后 再将其唤醒(notify);

**锁机制:**互斥锁可以避免数据被其他线程修改;读写锁可以多个线程同时读,但是不能写;条件变量一般与互斥锁一起使用,以原子方式阻塞进程,直到满足某个条件。

**信号量:**它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目 。信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源,这与操作系统中的PV操作相同。它指出了同时访问共享资源的线程最大数目。它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。

PV操作及信号量的概念都是由荷兰科学家E.W.Dijkstra提出的。信号量S是一个整数,S大于等于零时代表可供并发进程使用的资源实体数,但S小于零时则表示正在等待使用共享资源的进程数。

image-20210418115350354 image-20210418115407979 【问题6】线程有几种状态?or 生命周期 img

在 Java虚拟机 中,线程从最初的创建到最终的消亡,要经历若干个状态:

创建(new)、就绪(runnable/start)、运行(running)、

阻塞(blocked)、等待(waiting)、时间等待(time waiting) 和 消亡(dead/terminated)。

在给定的时间点上,一个线程只能处于一种状态,

新建状态: 使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。

就绪状态: 当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。该状态的线程位于可运行线程池中,等待被系统调度选中,获取cpu 的使用权 。

运行状态: 如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

阻塞状态:

如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。同步阻塞:线程在获取 synchronized同步锁失败(因为同步锁被其他线程占用)。其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。

死亡状态: 一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

img sleep():指定时间内让 当前正在执行的线程暂停执行,但不会释放“锁标志”。不推荐使用wait():当一个线程执行到wait()方法时(线程休眠且释放机锁),它就进入到一个和该对象相关的等待池中,同时失去了对象的机锁。当它被一个notify()方法唤醒时,等待池中的线程就被放到了锁池中。该线程从锁池中获得机锁,然后回到wait()前的中断现场。 (唤醒当前对象锁的等待线程使用notify或notifyAll方法)yield():暂停当前正在执行的线程对象。仅是释放线程占用的CPU资源,但却并未释放锁。join():等待该线程结束。让当前正在运行的线程等待,并且释放锁,等待调用join()的线程执行完毕。底层调用wait()方法。

https://blog.csdn.net/sinat_41144773/article/details/89532788?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control

多线程等待队列 【问题7】线程池

https://www.cnblogs.com/jiawen010/p/11855768.html

线程池的概念:

​ 线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。

线程池的工作机制

在线程池的编程模式下,任务是提交给整个线程池,而不是直接提交给某个线程,线程池在拿到任务后,就在内部寻找是否有空闲的线程,如果有,则将任务交给某个空闲的线程。

一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。

使用线程池的原因:

​ 多线程运行时间,系统不断的启动和关闭新线程,成本非常高,会过渡消耗系统资源,以及过渡切换线程的危险,从而可能导致系统资源的崩溃。这时,线程池就是最好的选择了。

【问题1】四种常见的线程池

CachedThreadPool:可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于耗时少,任务量大的情况。可缓存线程池,先查看池中有没有以前建立的线程,如果有,就直接使用。如果没有,就建一个新的线程加入池中,缓存型池子通常用于执行一些生存期很短的异步型任务

SecudleThreadPool**:周期性执行任务的线程池**,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。

SingleThreadPool:只有一条线程来执行任务,适用于有顺序的任务的应用场景。

FixedThreadPool:定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程 ———————————————— 版权声明:本文为CSDN博主「weixin_40271838」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_40271838/article/details/79998327

(2)进程有几种状态

就绪状态:具备运行条件但由于无CPU,暂时不能运行(进程已获得除处理机以外的所需资源,等待分配处理机资源)

运行状态:进程已经占有CPU,在CPU上运行,处于此状态的进程数小于等于CPU数;

阻塞状态:因为等待某项服务完成或信号而不能运行的状态。如等待:系统调用,I/O操作,合作进程信号…

进程的三种状态.jpg-14.1kB image-20210410163524095 (3)进程间的通信的几种方式

管道(pipe):半双工方式。通常是父子进程间的单向数据流动。

有名管道(named pipe):半双工方式。有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;

信号(signal):信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;

**消息队列:**消息队列是消息的链接表,消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。具有写权限得进程可以按照一定的规则向消息队列中添加新信息;对消息队列有读权限得进程则可以从消息队列中读取信息

共享内存:可以说这是最有用的进程间通信方式。速度快、效率高;需要同步机制。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。(这种方式需要依靠某种同步操作,如互斥锁和信号量等)

**信号量(semaphore):**信号量是一个计数器,用来控制多个进程对共享资源的访问。常作为一种锁机制。主要作为进程之间及同一种进程的不同线程之间的同步和互斥手段。

**套接字:**这是一种更为一般得进程间通信机制,它可用于网络中不同主机间的进程间通信,应用非常广泛。

(4)进程调度策略

FCFS(先来先服务,队列实现,非抢占的):先请求CPU的进程先分配到CPU

SJF(最短作业优先调度算法):参考运行时间,选取运行时间最短的作业投入运行。

易于实现,效率不高

忽视了作业等待时间,一个早来但是很长的作业将会在很长时间得不到调度,易出现资源“饥饿”的现象

优先级调度算法(可以是抢占的,也可以是非抢占的):根据进程优先数,把CPU分配给最高的进程。(优先级越高越先分配到CPU,相同优先级先到先服务)

存在的主要问题是:低优先级进程无穷等待CPU,会导致无穷阻塞或饥饿。解决方案:老化

进程优先数 = 静态优先数 +动态优先数

时间片轮转调度算法(可抢占的):

把所有就绪进程按先进先出的原则排成队列。新来进程加到队列末尾。

进程以时间片q为单位轮流使用CPU。刚刚运行一个时间片的进程排到队列末尾,等候下一轮运行。

队列逻辑上是环形的。

**高响应比优先(HRRN,Highest Response Ratio Next):**计算每个作业的响应比,选择响应比最高的作业优先投入运行。

响应比 = 1 + 等待时间 / 运行时间

可变时间片轮转调度

多重时间片循环调度法

【问题】抢占式与非抢占式的对比:

非抢占式(Nonpreemptive):让进程运行直到结束或阻塞的调度方式 容易实现 适合专用系统,不适合通用系统

抢占式(Preemptive):允许将逻辑上可继续运行的在运行过程暂停的调度方式 可防止单一进程长时间独占CPU系统开销大

(降低途径:硬件实现进程切换,或扩充主存以贮存大部分程序)

(5)死锁

死锁:两个或多个进程无限期地相互等待永远不会发生的条件的一种系统状态。【结果:每个进程都永远阻塞】

**死锁产生的原因:**资源有限,并发进程的推进顺序不当

【问题1】死锁产生的四个必要条件

**互斥:**至少有一个资源必须属于非共享模式,即一次只能被一个进程使用;若其他申请使用该资源,那么申请进程必须等到该资源被释放为止;

不剥夺条件:进程不能被抢占,即资源只能被进程在完成任务后自愿释放(进程在访问完资源前不能被其他进程强行剥夺。)

部分分配条件:进程边运行边申请资源,临时需要临时分配(区别于全部分配)

环路:若干进程之间形成一种头尾相接的环形等待资源关系 。

(多个进程构成环路:环中每个进程已占用的资源被前一进程申请,而自己所申请资源又被环中后一进程占用着)

**预防死锁:**破坏产生死锁的四个 必要条件之一即可。

**死锁的避免:**银行家算法,该方法允许进程动态地申请资源,系统在进行资源分配之前,先计算资源分配的安全性。若此次分配不会导致系统从安全状态向不安全状态转换,便可将资源分配给进程;否则不分配资源,进程必须阻塞等待。从而避免发生死锁。

image-20210410185253354 【问题2】操作系统里解决死锁的办法

https://www.cnblogs.com/yichengming/p/11450413.html

死锁预防----破坏四个必要条件

死锁避免----死锁避免是利用额外的检验信息,在分配资源时判断是否会出现死锁,只在不会出现死锁的情况下才分配资源。

两种避免办法

1、如果一个进程的请求会导致死锁,则不启动该进程。

2、如果一个进程的增加资源请求会导致死锁,则拒绝该申请。

避免死锁的具体实现通常利用银行家算法

检测和恢复死锁机制

允许系统进入死锁,如果利用死锁检测算法检测出系统已经出现了死锁,那么,此时就需要对系统采取相应的措施。常用的解除死锁的方法:

1)抢占资源:从一个或多个进程中抢占足够数量的资源分配给死锁进程,以解除死锁状态。

2)终止(或撤销)进程:终止或撤销系统中的一个或多个死锁进程,直至打破死锁状态。

检测和恢复死锁机制

缺点1:检测方法复杂,实现难度大。缺点2:恢复方法靠人工。撤消一些进程,回收资源再分配。

预先静态分配法(破坏部分分配条件)

进程运行前将所需资源一次性全部分配给它。因此进程在运行过程中不再提出资源请求,从而避免出现阻塞或者死锁。

有序资源分配法(破坏环路条件,使得环路无法构成)

image-20210410185845394 image-20210410185900485 【例子】:“哲学家进餐”问题

有五个哲学家,他们的生活方式是交替地进行思考和进餐。他们共用一张圆桌,分别坐在五张椅子上。

在圆桌上有五个碗和五支筷子,平时一个哲学家进行思考,饥饿时便试图取用其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐。进餐完毕,放下筷子又继续思考。

哲学家进餐问题的改进解法 方法一:至多只允许四位哲学家同时去拿左筷子,最终能保证至少有一位哲学家能进餐,并在用完后释放两只筷子供他人使用。方法二:仅当哲学家的左右手筷子都拿起时才允许进餐。方法三:规定奇数号哲学家先拿左筷子再拿右筷子,而偶数号哲学家相反。 (6)用户态和内核态

**内核态:**cpu可以访问内存的所有数据,包括外围设备,例如硬盘,网卡,cpu也可以将自己从一个程序切换到另一个程序。 **用户态:**只能受限的访问内存,且不允许访问外围设备,占用cpu的能力被剥夺,cpu资源可以被其他程序获取。

Intel的X86架构的CPU提供了0到3四个特权级,数字越小,特权越高,Linux操作系统中主要采用了0和3两个特权级,分别对应的就是内核态和用户态。

运行于用户态的进程可以执行的操作和访问的资源都会受到极大的限制

运行在内核态的进程则可以执行任何操作并且在资源的使用上没有限制。

很多程序开始时运行于用户态,但在执行的过程中,一些操作需要在内核权限下才能执行,这就涉及到一个从用户态切换到内核态的过程

【问题1】到底在什么情况下会发生从用户态到内核态的切换

一般存在以下三种情况:(系统调用可以认为是用户进程主动发起的,异常和外围设备中断则是被动的。)

1)当然就是系统调用:这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,比如前例中fork()实际上就是执行了一个创建新进程的系统调用。而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。

2)异常事件: 当CPU正在执行运行在用户态的程序时,突然发生某些预先不可知的异常事件,这个时候就会触发从当前用户态执行的进程转向内核态执行相关的异常事件,典型的如缺页异常。

3)外围设备的中断:当外围设备完成用户的请求操作后,会像CPU发出中断信号,此时,CPU就会暂停执行下一条即将要执行的指令,转而去执行中断信号对应的处理程序,如果先前执行的指令是在用户态下,则自然就发生从用户态到内核态的转换。

注意:系统调用的本质其实也是中断,相对于外围设备的硬中断,这种中断称为软中断,这是操作系统为用户特别开放的一种中断,如Linux int 80h中断。所以,从触发方式和效果上来看,这三种切换方式是完全一样的,都相当于是执行了一个中断响应的过程。但是从触发的对象来看,系统调用是进程主动请求切换的,而异常和硬中断则是被动的。

(7)CPU资源分配

进程是操作系统资源分配的基本单位,所以我觉得这里可以结合进程调度策略来回答

资源的动态分配:进程所需的资源是在进程运行中根据运行情况动态的分配、使用和释放的。

静态分配:批处理操作系统中,对作业一级采用资源静态分配方法。作业所需要的资源是在调度到这个作业的时候,根据用户给出的信息进行分配,并在做作业运行完毕后释放所获得的的全部资源。

【问题1】资源分配策略

体现在资源请求队列的排序原则上:

先请求先服务策略(FIFO) ①排序原则——按请求的先后次序排序:每一个新产生的请求均排在资源请求队列的队尾。 ②资源可用时的处理:资源可用时,取资源请求队列队首元素,将该资源分配给请求者。

优先调度策略 ①排序原则——按请求的优先级高低排序 对每一个进程制定一个优先级 按优先级的高低排序——每一个新产生的请求按对应进程的优先级高低插入到队列的相应位置。

针对设备特性的调度策略 调度目标:当有大量的I/O请求时,降低完成这些I/O服务的总时间 **移臂调度:**最短寻道时间优先算法(SSTF)、扫描算法(SCAN)

​ 在满足一个磁盘的请求时,总是选取与当前移动臂前进方向上最近的那个情求,使移臂距离最短 **旋转调度:**在满足一个磁盘请求时,总是选取与当前读写头旋转方向最近的那个情求,使旋转圈数最少

【问题2】资源分类

资源可以分为两类:可重用资源和消耗资源。

1.可重用资源有这么一些特点:

资源不能被删除且在任何时刻只能由一个进程所使用;

进程释放该资源后,其他的进程可重用。

可重用的资源在硬件层面上的有:处理器、I / O 通道、主和副存储器、设备等;在软件层面上的有:文件、数据库和信号量等数据结构。

2**.消耗资源**则有如下特点:

资源需要创建才能使用,用完之后需要进行销毁;

消耗资源有这些:在I / O缓冲区的中断、信号、消息等。

(8)同步 VS 异步

**同步(synchronize):**执行有先后顺序

**异步:**执行没有先后顺序,各执行各的,效率高

【问题1】线程共享资源会出现什么后果

当多线程访问同一段资源时,可能产生线程安全问题。这时候,我们需要将异步的访问操作变成同步的。

异步 --------> 同步

即对于这段资源的引用多线程要有先后顺序的访问。一个线程访问结束,另一个线程才能访问

解决线程安全问题方法:

对访问数据的逻辑加锁,使其访问变成同步操作

关键字synchronize(同步化)

synchronize可以修饰方法,那么该方法就是同步的。换句话说,该方法同一时间内只可能有一个线程执行这个方法的逻辑。

【问题2】线程同步的方式有哪些? 临界区

临界区是一段代码,在临界区内进程将访问临界资源。任何时候最多只有一个进程可以进入临界区,也就是说,临界区具有排他性。所以,为了互斥访问临界资源,每个进程在进入临界区之前,需要先进行检查。

互斥量

就是使用一个互斥的变量来直接制约多个进程,每个进程只有拥有这个变量才具有访问公共资源的权限,因为互斥量只有一个,所以能保证资源的正确访问。

信号量

信号量(Semaphore)是一个整型变量,可以对其执行自增和自减操作,自减操作通常也叫做P操作,自增操作也称为V操作。这两个操作需要被设计成原语,是不可分割,通常的做法是在执行这些操作的时候屏蔽中断。进程使用这两个操作进行同步。

对于P操作,如果执行操作后信号量小于 0,那么执行该操作的进程就会阻塞,否则继续执行;对于V操作,如果操作之后的信号量小于等于0,那么就会从阻塞队列唤醒一个进程。

线程间通信机制: (1)锁机制:互斥锁可以避免数据被其他线程修改;读写锁可以多个线程同时读,但是不能写;条件变量一般与互斥锁一起使用,以原子方式阻塞进程,直到满足某个条件。 (2)包括无名信号量和有名信号量 (3)信号机制:类似于进程间的信号处理。 线程间的通信主要用于线程间同步,而非数据传输。

(9)锁机制

临界资源[Critical Resource]: 一次只允许一个进程独占访问(使用)的资源

例:例子中的共享变量 i

临界区[Critical Section]: 进程中访问临界资源的程序段。

应用:

访问临界资源

访问临界区

步骤:

初始化锁的状态S = 1 ( 可用)

进入临界区之前执行**上锁Lock(s)**操作;

离开临界区之后执行**开锁unLock(s)**操作

image-20210410235153506

临界区和临界资源的访问特点

具有排他性

并发进程不能同时进入临界区

设计临界区访问机制的四个原则

忙则等待:当临界区忙时,其他进程必须在临界区外等待空闲让进:当无进程处于临界区时,任何有权进程可进入临界区。有限等待:进程进入临界区的请求应在有限时间内得到满足让权等待:等待进程放弃CPU。(让其它进程有机会得到CPU)。 (10)多线程加锁的3种方法

实现互斥访问的效果

对象锁(同步块)——锁某一个对象

对象锁:顾名思义给对象上锁

类锁——锁当前类(方法上有static关键字修饰)

类锁:顾名思义给类上锁–>具体就是给类的字节码上锁

实例锁——锁的是当前实例(方法上没有static修饰,表示只能锁当前实例)

同一个实力访问的线程才是安全的,不同的线程访问则不安全 (11)虚拟内存 1. 概念

虚拟内存允许执行进程不必完全在内存中。

虚拟内存的基本思想是:每个进程拥有独立的地址空间,这个空间被分为大小相等的多个块,称为页(Page),每个页都是一段连续的地址。这些页被映射到物理内存,但并不是所有的页都必须在内存中才能运行程序。当程序引用到一部分在物理内存中的地址空间时,由硬件立刻进行必要的映射;当程序引用到一部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入物理内存并重新执行失败的命令。这样,对于进程而言,逻辑上似乎有很大的内存空间,实际上其中一部分对应物理内存上的一块(称为帧,通常页和帧大小相等),还有一些没加载在内存中的对应在硬盘上,如图5所示。

这里写图片描述

虚拟内存实际上可以比物理内存大。当访问虚拟内存时,会访问MMU(内存管理单元)去匹配对应的物理地址(比如图5的0,1,2)。如果虚拟内存的页并不存在于物理内存中(如图5的3,4),会产生缺页中断,从磁盘中取得缺的页放入内存,如果内存已满,还会根据某种算法将磁盘中的页换出。

2. 页面置换算法

FIFO先进先出算法:在操作系统中经常被用到,比如作业调度(主要实现简单,很容易想到);

LRU(Least recently use)最近最少使用算法:根据使用时间到现在的长短来判断;

LFU(Least frequently use)最少使用次数算法:根据使用次数来判断;

OPT(Optimal replacement)最优置换算法:理论的最优,理论;就是要保证置换出去的是不再被使用的页,或者是在实际内存中最晚使用的算法。

4). 虚拟内存的应用与优点

虚拟内存很适合在多道程序设计系统中使用,许多程序的片段同时保存在内存中。当一个程序等待它的一部分读入内存时,可以把CPU交给另一个进程使用。虚拟内存的使用可以带来以下好处:

在内存中可以保留多个进程,系统并发度提高

解除了用户与内存之间的紧密约束,进程可以比内存的全部空间还大

3. 虚拟内存管理分类:

页式虚拟存储管理-----进程分页,内存分为若干物理页

image-20210411001918034 image-20210411001950350

段式虚拟存储管理-----进程分段

image-20210512210507661 image-20210512210618525 image-20210512210829055

段页式虚拟存储管理------在段中划分页面

image-20210512210423042 【问题1】分页和分段有什么区别(内存管理)?

段式存储管理是一种符合用户视角的内存分配管理方案。在段式存储管理中,将程序的地址空间划分为若干段(segment),如代码段,数据段,堆栈段;这样每个进程有一个二维地址空间,相互独立,互不干扰。段式管理的优点是:没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)

页式存储管理方案是一种用户视角内存与物理内存相分离的内存分配管理方案。在页式存储管理中,将程序的逻辑地址划分为固定大小的页(page),而物理内存划分为同样大小的帧,程序加载时,可以将任意一页放入内存中任意一个帧,这些帧不必连续,从而实现了离散分离。页式存储管理的优点是:没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满)。

【问题2】两者的不同点: 目的不同:分页是由于系统管理的需要而不是用户的需要,它是信息的物理单位;分段的目的是为了能更好地满足用户的需要,它是信息的逻辑单位,它含有一组其意义相对完整的信息;大小不同:页的大小固定且由系统决定,而段的长度却不固定,由其所完成的功能决定;地址空间不同: 段向用户提供二维地址空间;页向用户提供的是一维地址空间;信息共享:段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制;内存碎片:页式存储管理的优点是没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满);而段式管理的优点是没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)。 (12)进程通信和线程通信的区别

分别解释这两个通信就可

(13)如何保证线程安全 同步加锁


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3