说一下并行和并发的区别
并发:
你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。 (不一定是同时的)
你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。
并发的关键是你有处理多个任务的能力,不一定要同时。
并行的关键是你有同时处理多个任务的能力。
所以我认为它们最关键的点就是:是否是『同时』。
---------------------
作者:山鬼谣弋痕夕
来源:优快云
原文:https://blog.youkuaiyun.com/weixin_30363263/article/details/80732156
版权声明:本文为博主原创文章,转载请附上博文链接!
并发和并行从宏观上来讲都是同时处理多路请求的概念。但并发和并行又有区别,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。
在操作系统中,并发是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
你知道进程吗?有进程为何还有线程?
同步异步阻塞非阻塞IO
int state[N]; //跟踪每个哲学家的状态
semaphore mutex = 1; //筷子临界区的互斥锁
semaphore s[N]; //每个哲学家一个互斥锁
-
- 静态同步块
- C代码写了Printf(),解释从.c到.exe的过程?
- 一个程序从开始运行到结束的完整过程(四个过程)
- 内核态 vs 用户态
- 进程工作在用户空间下就叫用户态,工作在内核空间下就叫内核态。具体的说:
- 内核态:当一个进程执行系统调用而陷入内核代码中执行时,我们就称进程处于内核状态。此时处理器处于特权级最高的(0级)内核代码。进程可以执行指令集中的任何指令,可以访问系统中的任何内存位置。当进程处于内核态时,执行的内核代码会使用当前的内核栈。每个进程都有自己的内核栈。
- 用户态:当进程在执行用户自己的代码时,则称其处于用户态。即此时处理器在特权级最低的用户代码中运行。用户模式中的进程不允许执行特权指令,比如停止处理器,改变模式位,或者发起I/O操作。也不允许直接引用地址空间中内核区内的代码和数据。必须通过系统调用接口间接地访问内核代码和数据。
- 进程工作在用户空间下就叫用户态,工作在内核空间下就叫内核态。具体的说:
- 好处:通过内核态和用户态产生了一个保护机制,用户无法随意进入、修改所有进程共享的内核空间。
- 用户访问内核空间的方法
- 系统调用:如调用write(),read(),send()等IO函数等操作,进程就会进入内核态使用内核代码去完成操作。
- 异常:当CPU在执行运行在用户态的程序时,发现了某些事件不可知的异常,这是会触发由当前运行进程切换到处理此异常的内核相关程序中,也就到了内核态,比如缺页异常。
- 中断:当外围设备完成用户请求的操作之后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条将要执行的指令转而去执行中断信号的处理程序,如果先执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了有用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。
- 进程线程
- 进程和线程,区别
- 进程是资源分配的基本单位,进程是具有一定功能的程序关于某个数据集合上的一次运行活动(程序的一次运行)
- 线程是处理器调度的基本单位,是进程的实体,它是比进程更小的能独立运行的基本单位。
- 区别
- 进程是程序的一次执行,线程是进程中的执行单元;
- 资源:进程间是独立的,拥有独立的资源(内存空间、上下文),线程运行在进程中,不拥有资源,同一进程所产生的线程共享内存空间。
- 通信:进程间通信需要进程同步和互斥手段的辅助,以保证数据的一致性。而线程间可以通过直接读/写同一进程中的数据段(如全局变量)来进行通信(需要做好同步)。
- 系统开销:创建或撤销进程时,系统都要为之分配或回收资源(内存空间、I/O 设备等),所付出的开销远大于创建或撤销线程时的开销。类似地,在进行进程切换时,要保存当前进程 CPU 环境、设置新进程 CPU 环境,而线程切换时只需保存和设置少量寄存器内容, 开销很小。
- 调度:线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程内的线程切换到另一个进程中的线程时,会引起进程切换。
- 进程同步
- 临界区:每个进程中访问临界资源的那段程序(临界资源是共享资源,一次仅允许一个线程使用)。线程互斥地访问临界区。
- 有几种手段可以避免ab线程一起进入临界区域:
- 屏蔽中断,当一个进程进入临界区之后马上将系统所有中断屏蔽,等离开临界区域后再打开中断。当所有屏蔽被屏蔽后,包括时钟中断也会被屏蔽,CPU只有在时钟中断或者其他中断产生的时候才会在各个进程之间进行轮回。当中断被屏蔽以后,CPU就不可能让其他进程在运行,当然不会再有其他进程进入临界区域。只能通过硬件指令完成。
- 锁变量(不是原子性操作而翻车)
- 忙等待(用while不停检查turn直到turn为1)(不是原子性操作而翻车)
- Peterson解法
- 有几种手段可以避免ab线程一起进入临界区域:
- 同步&互斥
- 互斥:是指散布在不同任务之间的若干程序片断,当某个任务运行其中一个程序片段时,其它任务就不能运行它们之中的任一程序片段,只能等到该任务运行完这个程序片段后才可以运行。最基本的场景就是:一个公共资源同一时刻只能被一个进程或线程使用,多个进程或线程不能同时使用公共资源。
- 同步:是指散步在不同任务之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。最基本的场景就是:多个进程或线程在运行过程中按预定的先后次序运行。比如 A 任务的运行依赖于 B 任务产生的数据。
- 信号量
- 信号量(Semaphore)是一个整型变量,可以对其执行 down 和 up 操作(原语操作,屏蔽中断),也就是常见的 P 和 V 操作。
- down : 如果信号量大于0 ,执行-1操作;如果信号量小于等于 0,进程睡眠,直至信号量大于0时唤醒;
- up:对信号量执行 +1 操作,如果有睡眠进程,则唤醒。
- 如果信号量的取值只能为 0 或者 1,就成为了互斥量(Mutex) ,0表示临界区已经加锁,1表示临界区解锁。
- 信号量(Semaphore)是一个整型变量,可以对其执行 down 和 up 操作(原语操作,屏蔽中断),也就是常见的 P 和 V 操作。
- 管程
- 管程的重要特性:在一个时刻只能有一个进程使用管程。进程在无法继续执行的时候不能一直占用管程,否则其它进程永远不能使用管程。
- 管程引入了条件变量以及相关的操作:wait() 和 signal() 来实现同步操作。对条件变量执行 wait() 操作会导致调用进程阻塞,把管程让出来给另一个进程持有。signal() 操作用于唤醒被阻塞的进程。
- 临界区:每个进程中访问临界资源的那段程序(临界资源是共享资源,一次仅允许一个线程使用)。线程互斥地访问临界区。
- 经典同步问题
- 生产者-消费者问题
- 即有两个进程:生产者和消费者,共享一个固定大小的缓存。生产者制造一段数据,放进缓存。消费者一次移走一段数据。
- 问题的核心就是要保证不让制造商在缓存还是满的时候仍然要向内写数据,不让消费者试图从空的缓存中取出数据。
- 用信号量解决:(用了两个信号量)
- 缓冲区属于临界资源,需要使用一个互斥量 mutex 来控制对缓冲区的互斥访问。
- 为了同步生产者和消费者的行为,需要记录缓冲区中物品的数量。使用两个信号量:empty 记录空缓冲区的数量,full 记录满缓冲区的数量。其中,empty 信号量是在生产者进程中使用,当 empty 不为 0 时,生产者才可以放入物品;;full 信号量是在消费者进程中使用,当 full 信号量不为 0 时,消费者才可以取走物品。
- 死锁出现:注意,不能先对缓冲区进行加锁,再测试信号量。也就是说,不能先执行 down(mutex) 再执行 down(empty)。如果这么做了,那么可能会出现这种情况:生产者对缓冲区加锁后,执行 down(empty) 操作,发现 empty = 0,此时生产者睡眠。消费者不能进入临界区,因为生产者对缓冲区加锁了,消费者就无法执行 up(empty) 操作,empty 永远都为 0,导致生产者永远等待下,不会释放锁,消费者因此也会永远等待下去。
- 用管程解决:
- if count = N then wait(full);
- if count = 1 then signal(empty);
- 读者-写者问题
- 有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:
- ①允许多个读者可以同时对文件执行读操作;
- ②只允许一个写者往文件中写信息;
- ③任一写者在完成写操作之前不允许其他读者或写者工作;
- ④写者执行写操作前,应让已有的读者和写者全部退出。
- 读优先方法:一个整型变量 count 记录在对数据进行读操作的进程数量,一个互斥量 count_mutex 用于对 count 加锁,一个互斥量 data_mutex 用于对读写的数据加锁。
- 写优先方法:见pdf
- 更好的方法:见pdf
- 有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:
- 哲学家就餐问题
- 五个哲学家围着一张圆桌,每个哲学家面前放着食物。哲学家的生活有两种交替活动:吃饭以及思考。当一个哲学家吃饭时,需要先拿起自己左右两边的两根筷子,并且一次只能拿起一根筷子。
- 为了防止死锁的发生,可以设置两个条件:
- 必须同时拿起左右两根筷子; 只有在两个邻居都没有进餐的情况下才允许进餐。
- 生产者-消费者问题
- 进程通信
- 管道
- 管道通过调用 pipe 函数创建,fd[0] 用于读,fd[1] 用于写。
- 限制:
- 只支持双向交替传输(先A给B发,过一会交换,不能同时发);只能在父子进程中使用。
- FIFO 命名管道
- 管道
- 去除了管道只能在父子进程中使用的限制。
- FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据。
- 消息队列
- 相比于 FIFO,消息队列的优点:
- 消息队列可以独立于读写进程存在,从而避免了 FIFO 中同步管道的打开和关闭时可能产生的困难;
- 避免了 FIFO 的同步阻塞问题,不需要进程自己提供同步方法;读进程可以根据消息类型有选择地接收消息,而不像 FIFO 那样只能默认地接收。
- 相比于 FIFO,消息队列的优点:
- 信号量
- 它是一个计数器,用于为多个进程提供对共享数据对象的访问。
- 共享存储
- 允许多个进程共享一个给定的存储区。因为数据不需要在进程之间复制,所以这是最快的一种 IPC。
- 需要使用信号量用来同步对共享存储的访问。
- 多个进程可以将同一个文件映射到它们的地址空间从而实现共享内存。另外 XSI 共享内存不是使用文件,而是使用内存的匿名段。
- Socket套接字
- 与其它通信机制不同的是,它可用于不同机器间的进程通信。
- 进程调度算法
- (抢占式:A在运行,B来了之后强行把A中止之后运行B)
- 批处理系统 (吞吐量)
- 批处理系统中没有太多的用户操作,调度算法目标是保证吞吐量和周转时间(从提交到终止的时间)。
- 先来先服务 first-come first-serverd(FCFS)
- 按照请求的顺序进行调度。
- 有利于长作业,但不利于短作业,因为短作业必须一直等待前面的长作业执行完毕才能执行, 而长作业又需要执行很长时间,造成了短作业等待时间过长。
- 短作业优先 shortest job first(SJF)
- 按估计运行时间最短的顺序进行调度。
- 长作业有可能会饿死,处于一直等待短作业执行完毕的状态。因为如果一直有短作业到来,那么长作业永远得不到调度。
- 最短剩余时间优先 shortest remaining time next(SRTN)
- 调度程序总是选择剩余运行时间最短的那个进程运行。最短作业优先的抢占式版本。
- 交互式系统(快速响应)
- 交互式系统有大量的用户交互操作,在该系统中调度算法的目标是快速地进行响应。
- 时间片轮转
- 将所有就绪进程按先来先服务的原则排成一个队列,每次调度时,把 CPU 时间分配给队首进程,该进程可以执行一个时间片。当时间片用完时,由计时器发出时钟中断,调度程序便停止该进程的执行,并将它送往就绪队列的末尾,同时继续把 CPU 时间分配给队首的进程。
- 时间片轮转算法的效率和时间片的大小有很大关系:因为进程切换要保存进程的信息,并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程切换上就会花过多时间。 而如果时间片过长,那么实时性就不能得到保证。
- 优先级调度
- 为每个进程分配一个优先级,按优先级进行调度。
- 为了防止低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级。
- 高响应比优先调度算法
- 在批处理系统中,短作业优先算法是一种比较好的算法,其主要的不足之处是长作业的运行得不到保证。
- 因此为每个作业引入动态优先权,使作业的优先级随着等待时间的增加而以速率a提高,则长作业在等待一定的时间后,必然有机会分配到处理机。该优先权的变化规律可描述为:
- 如果作业的等待时间相同,则要求服务的时间愈短,其优先权愈高,因而该算法有利于短作业。
- 当要求服务的时间相同时,作业的优先权决定于其等待时间,等待时间愈长,其优先权愈高,因而它实现的是先来先服务。
- 多级反馈队列
- 多级反馈队列调度算法则不必事先知道各种进程所需的执行时间,而且还可以满足各种类型进程的需要,因而它是目前被公认的一种较好的进程调度算法。
- 设置多个就绪队列,并为各个队列赋予不同的优先级。第一个队列的优先级最高,第二个队列次之,其余各队列的优先权逐个降低。该算法赋予各个队列中进程执行时间片的大小也各不相同,在优先权愈高的队列中,为每个进程所规定的执行时间片就愈小。例如,第二个队列的时间片要比第一个队列的时间片长一倍,……,第i+1个队列的时间片要比第i个队列的时间片长一倍。
- 当一个新进程进入内存后,首先将它放入第一队列的末尾,按FCFS原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序便将该进程转入第二队列的末尾,再同样地按FCFS原则等待调度执行;如果它在第二队列中运行一个时间片后仍未完成,再依次将它放入第三队列,……,如此下去,当一个长作业(进程)从第一队列依次降到第n队列后,在第n 队列便采取按时间片轮转的方式运行。
- 仅当第一队列空闲时,调度程序才调度第二队列中的进程运行;仅当第1~(i-1)队列均空时,才会调度第i队列中的进程运行。如果处理机正在第i队列中为某进程服务时,又有新进程进入优先权较高的队列(第1~(i-1)中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即由调度程序把正在运行的进程放回到第i队列的末尾,把处理机分配给新到的高优先权进程。
- 怎样切换进程
- 上下文切换(切换过程在内核中进行)
- 操作系统保持跟踪进程运行所需的所有状态信息,这种状态就是上下文,它包括许多信息,例如PC和寄存器文件的当前值,以及主存的内容。
- 步骤:保存当前进程的上下文,恢复新进程的上下文,然后将控制权传递到新进程。新进程就会从上次停止的地方开始。
- 进程管理
- 进程、线程的状态(进程、线程的生命周期)
- ####线程状态以及API怎么操作会发生这种转换
- 创建状态:进程在创建时需要申请一个空白PCB,向其中填写控制和管理进程的信息,完成资源分配。如果创建工作无法完成,比如资源无法满足,就无法被调度运行,把此时进程所处状态称为创建状态
- 就绪状态:进程已经准备好,已分配到所需资源,只要分配到CPU就能够立即运行
- 执行状态:进程处于就绪状态被调度后,进程进入执行状态
- 阻塞状态:正在执行的进程由于某些事件(发出了I/O请求,申请缓存区失败)而暂时无法运行,进程受到阻塞。在满足请求时进入就绪状态等待系统调用
- 线程阻塞的原因:
- 等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
- 同步阻塞:线程获取synchronized同步锁失败(因为锁被其它线程所占用),进入同步阻塞状态;
- 其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
- 终止状态:进程结束,或出现错误,或被系统终止,进入终止状态。无法再执行
- 僵死状态(进程):一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
- 等待状态(线程):处于这种状态的线程不会被分配CPU执行时间,它们要等待被显式地唤醒,否则会处于无限期等待的状态。
- 计时(超时)等待(线程):处于这种状态的线程不会被分配CPU执行时间,不过无须无限期等待被其他线程显示地唤醒,在达到一定时间后它们会自动唤醒。
- 僵死进程怎么检测?
- 通过命令top来初步查看系统中僵尸进程的数目
- 查看具体信息可以用ps(僵尸进程的stat为Z)
- 避免产生僵死进程:在fork子进程之后wait。
- 通过杀死父进程来杀死僵死进程
- #守护进程 Daemon
- 也称为精灵进程,是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理发生的事件。 守护进程不受用户登陆与注销的影响,它一直运行着。Linux下的大多数服务器都是利用守护进程实现的。
- 守护线程
- t.setDaemon(true)
- 守护线程的唯一用途是为其他线程提供服务
-
- 锁
- 死锁是什么(哲学家就餐问题)
- 如果一个进程集合中的每个进程都在等待只能由该进程集合中的其他进程才能引发的事件,那么,该进程集合就是死锁的。
- 死锁的必要条件
- 互斥条件:每个资源要么已经分配给了一个进程,要么可用
- 占有和等待条件:已经得到了某个资源的进程可以再申请新的进程
- 不可抢占条件:已经分配给一个进程的资源不能强制性地被抢占,除非显示释放
- 环路等待条件:死锁发生时,系统中有两个或以上的进程组成一条环路,该环路中每个进程都在等待下一个进程所占资源
- 死锁的处理
- 死锁的预防
- 静态避免:破坏死锁的四个条件中的一个或几个。
- 互斥:不能破坏,它是设备的固有属性所决定的,不仅不能改变,还应该加以保证。
- 占有且等待:资源一次性分配——要求进程一次性的请求所有需要的资源,并且阻塞这个进程直到所有请求都同时满足。这个方法比较低效。
- 不可抢占:可剥夺资源:如果占有某些资源的一个进程进行进一步资源请求时被拒绝,则该进程必须释放它最初占有的资源。如果一个进程请求当前被另一个进程占有的一个资源,则操作系统可以抢占另外一个进程,要求它释放资源。
- 循环等待:资源有序分配法:通过定义资源类型的线性顺序来预防。如果一个进程已经分配了R类资源,那么接下来请求的资源只能是那些排在R类型之后的资源类型。该方法比较低效。
- 动态避免:银行家算法
- 操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程已占用的资源数与本次申请的资源数之和是否超过了该进程对资源的最大需求量。若超过则拒绝分配资源,若没有超过则再测试系统现存的资源能否满足该进程尚需的最大资源量,若能满足则按当前的申请量分配资源,否则也要推迟分配。
- 银行家算法在避免死锁角度上非常有效,但是需要在进程运行前就知道其所需资源的最大值,且进程数也通常不是固定的,因此使用有限,但从思想上可以提供了解,可以转换地应用在其他地方。
- 死锁的预防
- 死锁的检测与解除
- 资源分配图:
- 用圆圈代表一个进程,用框代表一类资源。由于一种类型的资源可能有多个,用框中的一个点代表一类资源中的一个资源。从进程到资源的有向边叫请求边,表示该进程申请一个单位的该类资源;从资源到进程的边叫分配边,表示该类资源已经有一个资源被分配给了该进程。
- 死锁定理:
- 当且仅当 S 状态的资源分配图是不可完全简化的,该条件为死锁定理。
- 简化方法如下:
- 在资源分配图中,找到既不阻塞又不是孤点的进程 Pi (即找出一条有向边与它相连,且该有向边对应资源的申请数量小于等于系统中已有空闲资源数量)。消去它所有的请求边和分配边,使之成为孤立的结点。
- 在这里要注意一个问题,判断某种资源是否有空闲,应该用它的资源数量减去它在资源分配图中的出度。
- 进程 Pi 所释放的资源,可以唤醒某些因等待这些资源而阻塞的进程,原来的阻塞进程可以变为非阻塞进程。根据(1)中的方法进行一系列简化后,若能消去图中所有的边,则称该图是可完全简化的。
- 死锁解除:
- 资源剥夺法:挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程。但应防止被挂起的进程长时间得不到资源,而处于资源匮乏的状态。
- 撤销进程法:强制撤销部分、甚至全部死锁进程,并剥夺这些进程的资源。撤销的原则可以按进程优先级和撤销进程代价的高低进行。
- 进程回退法:让一(或多)个进程回退到足以回避死锁的地步,进程回退时自愿释放资源而不是被剥夺。要求系统保持进程的历史信息,设置还原点。
- 消息队列的生产者消费者中消费者没有收到消息怎么办,消息有顺序比如1.2.3但是收到的却是1.3.2怎么办?消息发过来的过程中损坏或者出错怎么办
-
- 存储
- 内存管理机制
- 虚拟存储
- 为了在程序设计时不需要受到特定计算机物理内存大小的制约,以及让多个程序安全有效地共享主存,采用虚拟存储。
- 进程的目标代码被映射到同样的虚拟地址空间。虚拟存储机制为程序提供了一个极大的虚拟存储空间,它是主存和磁盘存储器的抽象。带来一个假象:每个进程都独占主存,且空间极大。好处有
- 每个进程有一致的虚拟地址空间,简化存储管理
- 把主存看作存储器的一个缓存,根据需要在磁盘和主存中交换信息,使得有限的主存空间充分利用
- 每个进程的虚拟地址空间私有,不会被别的进程破坏
- 虚拟存储的实现
- 分页
- 主存储器和虚拟地址空间都被划分成大小相等的页面,磁盘和主存之间按页为单位交换信息。虚拟地址空间中的页称为虚拟页,主存空间中的页称为页框。
- 主存中的页表管理了虚拟页与页框的一一对应关系。页表中存储了所有页的装入与否、修改、使用权限、在磁盘中的存放位置。地址转换MMU:以虚拟地址高位字段的虚拟页号作为索引,找到对应页表项,若装入位为1,则取出,并虚拟地址中的页内地址拼接,形成物理地址。否则进行缺页处理。
- 页面置换算法
- 最佳置换算法(OPT)(理想置换算法)
- 从主存中移出永远不再需要的页面;如无这样的页面存在,则选择最长时间不需要访问的页面。这样可以保证获得最低的缺页率。 是一种理论上的算法,因为无法知道一个页面多长时间不再被访问。
- 先进先出置换算法(FIFO)【性能差】
- 是最简单的页面置换算法。选择驻留主存时间最长的页面进行淘汰,即先进入主存的页面先淘汰。其理由是:最早调入主存的页面不再被使用的可能性最大。
- 最近最久未使用(LRU)算法【开销大】
- 当需要淘汰一个页面时,总是选择在最近一段时间内最久不用的页面予以淘汰。原因:利用局部性原理,根据一个作业在执行过程中过去的页面访问历史来推测未来的行为。它认为过去一段时间里不曾被访问过的页面,在最近的将来可能也不会再被访问。每次访问都需要更新链表,代价很高。
- 最少使用置换算法(LFU)
- 为每个页面配置一个计数器,一旦某页被访问,则将其计数器的值加1,在需要选择一页置换时,则将选择其计数器值最小的页面,即内存中访问次数最少的页面进行淘汰。
- 第二次机会算法
- FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问题,对该算法做一个简单的修改: 每个页面增加一个R位,当页面被访问 (读或写) 时设置该页面的 R 位为1。需要替换的时候,检查最老页面的 R 位。 如果 R 位是0,那么这个页面既老又没有被使用,可以立刻置换掉;如果是1,就将 R 位清0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。
- 时钟(CLOCK)置换算法:
- 环形链表的第二次机会算法,表针指向最老的页面
- 最佳置换算法(OPT)(理想置换算法)
- 分页
- 分段
- 根据程序的模块化特性,可按照程序的逻辑结构划分成多个相对独立的部分,例如,过程、数据表、数据阵列等,这些独立的部分称为段。段的长度可以动态增长。段与段之间的地址不连续,段内地址连续。
- 分页、分段比较
- 分页对程序员透明(程序员无需了解怎么分页,由编译器分),分段需要程序员显式划分。
- 分页是一维地址空间,分段是二维的。
- 页的大小不可变,段的大小可以动态改变。
- 分段可以对源程序以模块为单位进行分配、共享和保护。但由于段的长度各不相同,段的起点和终点不定,给主存空间分配带来麻烦,并且容易留下空白的零碎空间,造成浪费。
- 段页式
- 程序的地址空间划分成多个拥有独立地址空间的段,每个段上的地址空间划分成大小相同的页。兼具段、页的优点。
- 磁盘调度算法
- 读写一个磁盘块的时间的影响因素有:
- 旋转时间(主轴转动盘面,使磁头移动到适当的扇区上)
- 寻道时间(制动手臂移动,使磁头移动到适当的磁道上) 【寻道时间最长,主要目标是使平均寻道时间最短】
- 实际的数据传输时间
- 读写一个磁盘块的时间的影响因素有:
- 先来先服务 FCFS, First Come First Served
- 按照磁盘请求的顺序进行调度。
- 优点是公平和简单。缺点:未对寻道做任何优化,使平均寻道时间可能较长。
- 最短寻道时间优先 SSTF, Shortest Seek Time First
- 优先调度与当前磁头所在磁道距离最近的磁道。
- 虽然平均寻道时间比较低,但是不够公平。如果新到达的磁道请求总是比一个在等待的磁道请 、求近,那么在等待的磁道请求会一直等待下去,也就是出现饥饿现象。两边的磁道请求更容易出现饥饿现象。
- 电梯算法
- 电梯总是保持一个方向运行,直到该方向没有请求为止,然后改变运行方向。
- 因为考虑了移动方向,所有的磁盘请求都会被满足,解决了 SSTF 的饥饿问题。
- Buffer 和 Cache
- buffer和cache都是为了解决互访的两种设备存在速率差异,使磁盘的IO的读写性能或cpu更加高效,减少进程间通信等待的时间
- buffer:缓冲区-用于存储速度不同步的设备或优先级不同的设备之间传输数据,通过buffer可以减少进程间通信需要等待的时间,当存储速度快的设备与存储速度慢的设备进行通信时,存储快的设备先把数据缓存到buffer上,等到系统统一把buffer上的数据写到速度慢的设备上。常见的有把内存的数据往磁盘进行写操作,这时你可以查看一下buffers
- cache:缓存区-用于对读取速度比较严格,却因为设备间因为存储设备存在速度差异,而不能立刻获取数据,这时cache就会为了加速缓存一部分数据。常见的是CPU和内存之间的数据通信,因为CPU的速度远远高于主内存的速度,CPU从内存中读取数据需等待很长的时间,而Cache保存着CPU刚用过的数据或循环使用的部分数据,这时Cache中读取数据会更快,减少了CPU等待的时间,提高了系统的性能。
- 缓存数据处理【说的LRU】:cache、主存、磁盘的关系等等还要再补充!!
- 缓存cache命中和不命中
- cpu访问单元所在的主存块在cache中,则称为命中
- Icache & Dcache
- icache缓存指令
- dcache缓存数据
- cache:SRAM 主存储器(RAM&ROM):DRAM
- 几种级别Cache的大小
- 设计
- 递增id实现。我说用信号量。问我Atomic行不行,我说可以,CAS。问我CAS详细,问我1.8有没有别的方法,我不清楚。
- 单机两进程,B必须在A结束后才能进行业务,怎么同步。我说zookeeper临时节点;我说信号量,问我实现,不清楚;我说让A占用某一文件句柄,B检查该文件的使用者,问我linux是怎么实现的,我不清楚;我说用socket模型,让Abind在某端口,当A结束时,会释放该端口,并且异常下,OS也会关闭该端口,缺点是有延迟。问我延迟多少,我说应该是以s为单位,具体不清楚。问我在哪儿修改,我说不知道,我linux使用不多。
- 两个线程打印1.2.3.4打印到100怎么实现,这里刚开始说的是加锁用生产者消费者来做,后来说了semaphore,感觉后面的才是面试官想要的答案。