计算机操作系统

操作系统详解

1. 简单说下对并行和并发的理解

  1. 并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生;
  2. 并行是在不同实体上的多个事件,并发是在同一实体上的多个事件;

2. 同步、异步、阻塞、非阻塞的概念

  • 同步:当一个同步调用发出后,调用者要一直等待返回结果。通知后,才能进行后续的执行。
  • 异步:当一个异步过程调用发出后,调用者不能立刻得到返回结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。
  • 阻塞:是指调用结果返回前,当前线程会被挂起,即阻塞。
  • 非阻塞:是指即使调用结果没返回,也不会阻塞当前线程。

进程管理

3. 进程和线程的基本概念

  • 进程:进程是系统进行资源分配和调度的一个独立单位,是系统中的并发执行的单位。
  • 线程:线程是进程的一个实体,也是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位,有时又被称为轻权进程或轻量级进程。

4. 进程和线程的区别

进程和线程的关系

(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程是操作系统可识别的最小执行和调度单位。

(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。 同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量。

(3)处理机分给线程,即真正在处理机上运行的是线程。

(4)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。

进程与线程的区别?

  • 进程(Process)是系统进行资源分配和调度的基本单位,线程(Thread)是CPU调度和分派的基本单位;
  • 线程依赖于进程而存在,一个进程至少有一个线程;
  • 进程有自己的独立地址空间,线程共享所属进程的地址空间;
  • 进程是拥有系统资源的一个独立单位,而线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),和其他线程共享本进程的相关资源如内存、I/O、cpu等;
  • 在进程切换时,涉及到整个当前进程CPU环境的保存环境的设置以及新被调度运行的CPU环境的设置,而线程切换只需保存和设置少量的寄存器的内容,并不涉及存储器管理方面的操作,可见,进程切换的开销远大于线程切换的开销;
  • 线程之间的通信更方便,同一进程下的线程共享全局变量等数据,而进程之间的通信需要以进程间通信(IPC)的方式进行;
  • 多线程程序只要有一个线程崩溃,整个程序就崩溃了,但多进程程序中一个进程崩溃并不会对其它进程造成影响,因为进程有自己的独立地址空间,因此多进程更加健壮

用户线程和内核线程之间的关系

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

  • 进程代码段
  • 进程的公有数据(全局变量、静态变量...)
  • 进程打开的文件描述符
  • 进程的当前目录
  • 信号处理器/信号处理函数:对收到的信号的处理方式
  • 进程ID与进程组ID

5. 有了进程,为什么还要线程 ?

进程可以使多个程序并发执行,以提高资源的利用率和系统的吞吐量,但是其带来了一些缺点:

  1. 进程在同一时间只能干一件事情;
  2. 进程在执行的过程中如果阻塞,整个进程就会被挂起,即使进程中有些工作不依赖与等待的资源,仍然不会执行。

基于以上的缺点,操作系统引入了比进程粒度更小的线程,作为并发执行的基本单位,从而减少程序在并发执行时所付出的时间和空间开销,提高并发性能。

5. 上下文切换

对于单核单线程CPU而言,在某一时刻只能执行一条CPU指令。上下文切换(Context Switch)是一种将CPU资源从一个进程分配给另一个进程的机制。从用户角度看,计算机能够并行运行多个进程,这恰恰是操作系统通过快速上下文切换造成的结果。在切换的过程中,操作系统需要先存储当前进程的状态(包括内存空间的指针,当前执行完的指令等等),再读入下一个进程的状态,然后执行此进程。

5. 进程上下文和线程上下文

5. 为什么进程上下文切换比线程上下文切换代价高

进程切换分两步:

1.切换页目录以使用新的地址空间

2.切换内核栈和硬件上下文

对于linux来说,线程和进程的最大区别就在于地址空间,对于线程切换,第1步是不需要做的,第2是进程和线程切换都要做的。

切换的性能消耗:

1、线程上下文切换和进程上下问切换一个最主要的区别是线程的切换虚拟内存空间依然是相同的,但是进程切换是不同的。这两种上下文切换的处理都是通过操作系统内核来完成的。内核的这种切换过程伴随的最显著的性能损耗是将寄存器中的内容切换出。

2、另外一个隐藏的损耗是上下文的切换会扰乱处理器的缓存机制。简单的说,一旦去切换上下文,处理器中所有已经缓存的内存地址一瞬间都作废了。还有一个显著的区别是当你改变虚拟内存空间的时候,处理的页表缓冲(processor's Translation Lookaside Buffer (TLB))或者相当的神马东西会被全部刷新,这将导致内存的访问在一段时间内相当的低效。但是在线程的切换中,不会出现这个问题。

5.1 多进程和多线程编程的区别?

5.2 僵尸进程和孤儿进程

一、概念

孤儿进程:

 一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程:

 一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进

程。

二、危害

孤儿进程:

 孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程处理它的一切善后工作。因此孤儿进程并不会有什么危害。

僵尸进程:

 父进程还在运行但是子进程挂了,但是父进程却没有使用wait来清理子进程的进程信息,导致子进程虽然运行实体已经消失,但是仍然在内核的进程表中占据一条记录,这样长期下去对于系统资源是一个浪费。

三、僵尸进程处理

1、通过信号机制

 子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。调用wait()或者waitpid(),让父进程阻塞等待僵尸进程的出现,处理完在继续运行父进程。

2、杀死父进程

 当父进程陷入死循环等无法处理僵尸进程时,强制杀死父进程,那么它的子进程,即僵尸进程会变成孤儿进程,由系统来回收。

3、重启系统

 当系统重启时,所有进程在系统关闭时被停止,包括僵尸进程,开启时init进程会重新加载其他进程。

6. 进程的状态转换

进程包括三种状态:就绪态、运行态和阻塞态。

  1. 就绪 —> 执行:对就绪状态的进程,当进程调度程序按一种选定的策略从中选中一个就绪进程,为之分配了处理机后,该进程便由就绪状态变为执行状态;
  2. 执行 —> 阻塞:正在执行的进程因发生某等待事件而无法执行,则进程由执行状态变为阻塞状态,如进程提出输入/输出请求而变成等待外部设备传输信息的状态,进程申请资源(主存空间或外部设备)得不到满足时变成等待资源状态,进程运行中出现了故障(程序出错或主存储器读写错等)变成等待干预状态等等;
  1. 阻塞 —> 就绪:处于阻塞状态的进程,在其等待的事件已经发生,如输入/输出完成,资源得到满足或错误处理完毕时,处于等待状态的进程并不马上转入执行状态,而是先转入就绪状态,然后再由系统进程调度程序在适当的时候将该进程转为执行状态;
  2. 执行 —> 就绪:正在执行的进程,因时间片用完而被暂停执行,或在采用抢先式优先级调度算法的系统中,当有更高优先级的进程要运行而被迫让出处理机时,该进程便由执行状态转变为就绪状态。

7. 什么是系统调用?

根据进程访问资源的特点,我们可以把进程在系统上的运行分为两个级别:

  1. 用户态(user mode) : 用户态运行的进程或可以直接读取用户程序的数据。
  2. 系统态(kernel mode):可以简单的理解系统态运行的进程或程序几乎可以访问计算机的任何资源,不受限制。

说了用户态和系统态之后,那么什么是系统调用呢?

我们运行的程序基本都是运行在用户态,如果我们调用操作系统提供的系统态级别的子功能咋办呢?那就需要系统调用了!

也就是说在我们运行的用户程序中,凡是与系统态级别的资源有关的操作(如文件管理、进程控制、内存管理等),都必须通过系统调用方式向操作系统提出服务请求,并由操作系统代为完成。

这些系统调用按功能大致可分为如下几类:

  • 设备管理。完成设备的请求或释放,以及设备启动等功能。
  • 文件管理。完成文件的读、写、创建及删除等功能。
  • 进程控制。完成进程的创建、撤销、阻塞及唤醒等功能。
  • 进程通信。完成进程之间的消息传递或信号传递等功能。
  • 内存管理。完成内存的分配、回收以及获取作业占用内存区大小及地址等功能

7. 中断与系统调用?

所谓的中断就是在计算机执行程序的过程中,由于出现了某些特殊事情,使得CPU暂停对程序的执行,转而去执行处理这一事件的程序。等这些特殊事情处理完之后再回去执行之前的程序。中断一般分为三类:

  • 由计算机硬件异常或故障引起的中断,称为内部异常中断
  • 由程序中执行了引起中断的指令而造成的中断,称为软中断(这也是和我们将要说明的系统调用相关的中断);
  • 由外部设备请求引起的中断,称为外部中断。简单来说,对中断的理解就是对一些特殊事情的处理。

与中断紧密相连的一个概念就是中断处理程序了。当中断发生的时候,系统需要去对中断进行处理,对这些中断的处理是由操作系统内核中的特定函数进行的,这些处理中断的特定的函数就是我们所说的中断处理程序了。

另一个与中断紧密相连的概念就是中断的优先级。中断的优先级说明的是当一个中断正在被处理的时候,处理器能接受的中断的级别。中断的优先级也表明了中断需要被处理的紧急程度。每个中断都有一个对应的优先级,当处理器在处理某一中断的时候,只有比这个中断优先级高的中断可以被处理器接受并且被处理。优先级比这个当前正在被处理的中断优先级要低的中断将会被忽略。

典型的中断优先级如下所示:

  • 机器错误 > 时钟 > 磁盘 > 网络设备 > 终端 > 软件中断

在讲系统调用之前,先说下进程的执行在系统上的两个级别:用户级和核心级,也称为用户态和系统态(user mode and kernel mode)

           用户空间就是用户进程所在的内存区域,相对的,系统空间就是操作系统占据的内存区域。用户进程和系统进程的所有数据都在内存中。处于用户态的程序只能访问用户空间,而处于内核态的程序可以访问用户空间和内核空间。

用户态切换到内核态的方式如下:

  • 系统调用:程序的执行一般是在用户态下执行的,但当程序需要使用操作系统提供的服务时,比如说打开某一设备、创建文件、读写文件(这些均属于系统调用)等,就需要向操作系统发出调用服务的请求,这就是系统调用。
  • 异常:当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。
  • 外围设备的中断:当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。

用户态和核心态(内核态)之间的区别是什么呢?

       权限不一样。

  • 用户态的进程能存取它们自己的指令和数据,但不能存取内核指令和数据(或其他进程的指令和数据)
  • 核心态下的进程能够存取内核和用户地址某些机器指令是特权指令,在用户态下执行特权指令会引起错误。在系统中内核并不是作为一个与用户进程平行的估计的进程的集合。

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

IO多路复用(IO Multiplexing)是指单个进程/线程就可以同时处理多个IO请求。

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

select/poll/epoll区别

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  • select:将文件描述符放入一个集合中,调用select时,将这个集合从用户空间拷贝到内核空间(缺点1:每次都要复制,开销大),由内核根据就绪状态修改该集合的内容。(缺点2)集合大小有限制,32位机默认是1024(64位:2048);采用水平触发机制。select函数返回后,需要通过遍历这个集合,找到就绪的文件描述符(缺点3:轮询的方式效率较低),当文件描述符的数量增加时,效率会线性下降;

select 允许应用程序监视一组文件描述符,等待一个或者多个描述符成为就绪状态,从而完成 I/O 操作。

fd_set 使用数组实现,数组大小使用 FD_SETSIZE 定义,所以只能监听少于 FD_SETSIZE 数量的描述符。有三 种类型的描述符类型:readset、writeset、exceptset,分别对应读、写、异常条件的描述符集合。

timeout 为超时参数,调用 select 会一直阻塞直到有描述符的事件到达或者等待的时间超过 timeout。

成功调用返回结果大于 0,出错返回结果为 -1,超时返回结果为 0。

int poll(struct pollfd *fds, unsigned int nfds, int timeout);
  • poll:和select几乎没有区别,区别在于文件描述符的存储方式不同,poll采用链表的方式存储,没有最大存储数量的限制;
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
  • epoll:通过内核和用户空间共享内存,避免了不断复制的问题;支持的同时连接数上限很高(1G左右的内存支持10W左右的连接数);文件描述符就绪时,采用回调机制,避免了轮询(回调函数将就绪的描述符添加到一个链表中,执行epoll_wait时,返回这个链表);支持水平触发和边缘触发,采用边缘触发机制时,只有活跃的描述符才会触发回调函数。

epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护 在一棵红黑树上,通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理,进程调用 epoll_wait() 便可以得到事件完成的描述符。

从上面的描述可以看出,epoll 只需要将描述符从进程缓冲区向内核缓冲区拷贝一次,并且进程不需要通过轮询来获得事件完成的描述符。

总结,区别主要在于:

  • 一个线程/进程所能打开的最大连接数
  • 文件描述符传递方式(是否复制)
  • 水平触发 or 边缘触发
  • 查询就绪的描述符时的效率(是否轮询)

什么时候使用select/poll,什么时候使用epoll

当连接数较多并且有很多的不活跃连接时,epoll的效率比其它两者高很多;但是当连接数较少并且都十分活跃的情况下,由于epoll需要很多回调,因此性能可能低于其它两者。

1. select 应用场景

select 的 timeout 参数精度为微秒,而 poll 和 epoll 为毫秒,因此 select 更加适用于实时性要求比较高的场景,比如核反应堆的控制。

select 可移植性更好,几乎被所有主流平台所支持。

2. poll 应用场景

poll 没有最大描述符数量的限制,如果平台支持并且对实时性要求不高,应该使用 poll 而不是 select。

3. epoll 应用场景

只需要运行在 Linux 平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接。

需要同时监控小于 1000 个描述符,就没有必要使用 epoll,因为这个应用场景下并不能体现 epoll 的优势。

需要监控的描述符状态变化多,而且都是非常短暂的,也没有必要使用 epoll。因为 epoll 中的所有描述符都存储在内核中,造成每次需要对描述符的状态改变都需要通过 epoll_ctl() 进行系统调用,频繁系统调用降低效率。并且 epoll 的描述符存储在内核,不容易调试。

什么是文件描述符?

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

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

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

  • 水平触发(LT,Level Trigger)模式下,只要一个文件描述符就绪,就会触发通知,如果用户程序没有一次性把数据读写完,下次还会通知;
  • 边缘触发(ET,Edge Trigger)模式下,当描述符从未就绪变为就绪时通知一次,之后不会再通知,直到再次从未就绪变为就绪(缓冲区从不可读/写变为可读/写)。
  • 区别:边缘触发效率更高,减少了被重复触发的次数,函数不会返回大量用户程序可能不需要的文件描述符。
  • 为什么边缘触发一定要用非阻塞(non-block)IO:避免由于一个描述符的阻塞读/阻塞写操作让处理其它描述符的任务出现饥饿状态

有哪些常见的IO模型

  • 同步阻塞IO(Blocking IO):用户线程发起IO读/写操作之后,线程阻塞,直到可以开始处理数据;对CPU资源的利用率不够;
  • 同步非阻塞IO(Non-blocking IO):发起IO请求之后可以立即返回,如果没有就绪的数据,需要不断地发起IO请求直到数据就绪;不断重复请求消耗了大量的CPU资源;
  • IO多路复用:使用 select 或者 poll 等待数据,并且可以等待多个套接字中的任何一个变为可读。这一过程会被阻塞,当某一个套接字可读时返回,之后再使用 recvfrom 把数据从内核复制到进程中。
  • 异步IO(Asynchronous IO):用户线程发出IO请求之后,继续执行,由内核进行数据的读取并放在用户指定的缓冲区内,在IO完成之后通知用户线程直接使用

7. 线程同步方式有哪些?

  • 互斥量 Mutex:互斥量是内核对象,只有拥有互斥对象的线程才有访问互斥资源的权限。因为互斥对象只有一个,所以可以保证互斥资源不会被多个线程同时访问;当前拥有互斥对象的线程处理完任务后必须将互斥对象交出,以便其他线程访问该资源;
  • 信号量 Semaphore:信号量是内核对象,它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。信号量对象保存了最大资源计数当前可用资源计数,每增加一个线程对共享资源的访问,当前可用资源计数就减1,只要当前可用资源计数大于0,就可以发出信号量信号,如果为0,则将线程放入一个队列中等待。线程处理完共享资源后,应在离开的同时通过ReleaseSemaphore函数将当前可用资源数加1。如果信号量的取值只能为0或1,那么信号量就成为了互斥量;
  • 事件 Event:允许一个线程在处理完一个任务后,主动唤醒另外一个线程执行任务。事件分为手动重置事件和自动重置事件。手动重置事件被设置为激发状态后,会唤醒所有等待的线程,而且一直保持为激发状态,直到程序重新把它设置为未激发状态。自动重置事件被设置为激发状态后,会唤醒一个等待中的线程,然后自动恢复为未激发状态。
  • 临界区 Critical Section:任意时刻只允许一个线程对临界资源进行访问。拥有临界区对象的线程可以访问该临界资源,其它试图访问该资源的线程将被挂起,直到临界区对象被释放

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

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

7. 进程间的通信方式有哪些?

https://www.cnblogs.com/zgq0/p/8780893.html

进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。IPC 的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams 等。其中 Socket 和 Streams 支持不同主机上的两个进程 IPC。

  • 管道
  • 它是半双工的,具有固定的读端和写端;
  • 它只能用于父子进程或者兄弟进程之间的进程的通信;
  • 它可以看成是一种特殊的文件,对于它的读写也可以使用普通的 read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中

优点:简单方便

缺点:

  1. 局限于单向通信
    1. 只能创建在它的进程以及其有亲缘关系的进程之间
  2. 缓冲区有限
  • 命名管道
    • FIFO 可以在无关的进程之间交换数据,与无名管道不同;
    • FIFO 有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。
  • 优点:可以实现任意关系的进程间的通信
  • 缺点:
  1. 长期存于系统中,使用不当容易出错
  2. 缓冲区有限
  • 消息队列
    • 消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符 ID 来标识;
    • 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级
    • 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除;
    • 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
  • 优点:可以实现任意进程间的通信,并通过系统调用函数来实现消息发送和接收之间的同步,无需考虑同步问题,方便
  • 缺点:信息的复制需要额外消耗 CPU 的时间,不适宜于信息量大或操作频繁的场合
  • 信号量
  • 信号量(semaphore)是一个计数器。用于实现进程间的互斥与同步,而不是用于存储进程间通信数据;
  • 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存
  • 信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作
  • 每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数;
  • 支持信号量组。
  • 优点:可以同步进程
  • 缺点:信号量有限
  • 共享内存
  •         共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区;
    • 共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
  • 优点:无须复制,快捷,信息量大
  • 缺点:
    1. 通信是通过将共享空间缓冲区直接附加到进程的虚拟地址空间中来实现的,因此进程间的读写操作的同步问题
    2. 利用内存缓冲区直接交换信息,内存的实体存在于计算机中,只能同一个计算机系统中的诸多进程共享,不方便网络通信

套接字(Socket):可用于不同计算机间的进程通信

  • 优点:
    1. 传输数据为字节级,传输数据可自定义,数据量小效率高
    2. 传输数据时间短,性能高
    1. 适合于客户端和服务器端之间信息实时交互
    2. 可以加密,数据安全性强
  • 缺点:需对传输的数据进行解析,转化成应用级的数据。

管道(pipe):管道允许一个进程和另一个与它有共同祖先的进程之间进行通信;

命名管道(FIFO):类似于管道,但是它可以用于任何两个进程之间的通信,命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建;

信号(signal):信号是比较复杂的通信方式,用于通知接收进程有某种事情发生,除了用于进程间通信外,进程还可以发送信号给进程本身;Linux除了支持UNIX早期信号语义函数signal外,还支持语义符合POSIX.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD即能实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数的功能);

内存映射(mapped memory):内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它;

消息队列(message queue):消息队列是消息的连接表,包括POSIX消息对和System V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能成该无格式字节流以及缓冲区大小受限等缺点;

信号量(semaphore):信号量主要作为进程间以及同进程不同线程之间的同步手段;

共享内存 (shared memory):它使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。这是针对其他通信机制运行效率较低而设计的。它往往与其他通信机制,如信号量结合使用,以达到进程间的同步及互斥;

套接字(Socket):它是更为通用的进程间通信机制,可用于不同机器之间的进程间通信。起初是由UNIX系统的BSD分支开发出来的,但现在一般可以移植到其他类UNIX系统上:Linux和System V的变种都支持套接字;

8. 线程间的通信方式有哪些?

  • 锁机制:包括互斥锁/量(mutex)、读写锁(reader-writer lock)、自旋锁(spin lock)、条件变量(condition)
    • 互斥锁/量(mutex):提供了以排他方式防止数据结构被并发修改的方法。
    • 读写锁(reader-writer lock):允许多个线程同时读共享数据,而对写操作是互斥的。
    • 自旋锁(spin lock)与互斥锁类似,都是为了保护共享资源。互斥锁是当资源被占用,申请者进入睡眠状态;而自旋锁则循环检测保持者是否已经释放锁。
    • 条件变量(condition):可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
  • 信号量机制(Semaphore)
    • 无名线程信号量
    • 命名线程信号量
  • 信号机制(Signal):类似进程间的信号处理
  • 屏障(barrier):屏障允许每个线程等待,直到所有的合作线程都达到某一点,然后从该点继续执行。

线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制

8. 进程的调度方法有哪些?

进程调度(低级调度):是把就绪队列中的进程进行调度,使得进程获得CPU资源,状态上:就绪态->运行态

内存调度(中级调度):是把挂起队列中的进程唤醒,把进程从外存调入内村,状态上:挂起态 -> 就绪态

作业调度(高级调度):是把后备队列中的作业调入内存,并为其创建进程,状态上:无 -> 创建态 -> 就绪态

调度算法是指:根据系统的资源分配策略所规定的资源分配算法。常用的调度算法有:先来先服务调度算法、时间片轮转调度法、短作业优先调度算法、最短剩余时间优先、高响应比优先调度算法、优先级调度算法等等。

https://www.cnblogs.com/szitcast/p/10927375.html


  • 先来先服务调度算法
  • 短作业(SJF)优先调度算法
  • 最短剩余时间优先
  • 高响应比优先调度算法

  • 时间片轮转调度法
  • 优先级调度算法
  • 多级反馈队列调度算法

  • 先到先服务(FCFS)调度算法 : 从就绪队列中选择一个最先进入该队列的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用CPU时再重新调度。
  • 短作业优先(SJF)的调度算法 : 从就绪队列中选出一个估计运行时间最短的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用CPU时再重新调度。
  • 时间片轮转调度算法 : 时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法,又称RR(Round robin)调度。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。
  • 多级反馈队列调度算法 :前面介绍的几种进程调度的算法都有一定的局限性。如短进程优先的调度算法,仅照顾了短进程而忽略了长进程 。多级反馈队列调度算法既能使高优先级的作业得到响应又能使短作业(进程)迅速完成。,因而它是目前被公认的一种较好的进程调度算法,UNIX操作系统采取的便是这种调度算法。
  • 优先级调度 :为每个流程分配优先级,首先执行具有最高优先级的进程,依此类推。具有相同优先级的进程以FCFS方式执行。可以根据内存要求,时间要求或任何其他资源要求来确定优先级。
  1. 批处理系统

批处理系统没有太多的用户操作,在该系统中,调度算法目标是保证吞吐量和周转时间(从提交到终止的时间)

先来先服务 first-come first-serverd(FCFS)

按照请求的顺序进行调度。非抢占式,开销小,无饥饿问题,响应时间不确定(可能很慢);

对短进程不利,对IO密集型进程不利。

最短作业优先 shortest job first(SJF)

按估计运行时间最短的顺序进行调度。非抢占式,吞吐量高,开销可能较大,可能导致饥饿问题;

对短进程提供好的响应时间,对长进程不利。

最短剩余时间优先 shortest remaining time next(SRTN)

按剩余运行时间的顺序进行调度。(最短作业优先的抢占式版本)。吞吐量高,开销可能较大,提供好的响应时间;

可能导致饥饿问题,对长进程不利。

最高响应比优先 Highest Response Ratio Next(HRRN)

响应比 = 1+ 等待时间/处理时间。同时考虑了等待时间的长短和估计需要的执行时间长短,很好的平衡了长短进程。非抢占,吞吐量高,开销可能较大,提供好的响应时间,无饥饿问题。

  1. 交互式系统
    交互式系统有大量的用户交互操作,在该系统中调度算法的目标是快速地进行响应。

时间片轮转 Round Robin

将所有就绪进程按 FCFS 的原则排成一个队列,用完时间片的进程排到队列最后。抢占式(时间片用完时),开销小,无饥饿问题,为短进程提供好的响应时间;

若时间片小,进程切换频繁,吞吐量低;若时间片太长,实时性得不到保证。

优先级调度算法

为每个进程分配一个优先级,按优先级进行调度。为了防止低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级。

多级反馈队列调度算法 Multilevel Feedback Queue

设置多个就绪队列1、2、3...,优先级递减,时间片递增。只有等到优先级更高的队列为空时才会调度当前队列中的进程。如果进程用完了当前队列的时间片还未执行完,则会被移到下一队列。

抢占式(时间片用完时),开销可能较大,对IO型进程有利,可能会出现饥饿问题

9. 什么是死锁?

死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。 如果此时有一个线程 A,已经持有了锁 A,但是试图获取锁 B,线程 B 持有锁 B,而试图获取锁 A,这种情况下就会产生死锁。

10. 什么是用户态和内核态?

为了限制不同程序的访问能力,防止一些程序访问其它程序的内存数据,CPU划分了用户态和内核态两个权限等级。

  • 用户态只能受限地访问内存,且不允许访问外围设备,没有占用CPU的能力,CPU资源可以被其它程序获取;
  • 内核态可以访问内存所有数据以及外围设备,也可以进行程序的切换。

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

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

  • 安全性:防止用户程序恶意或者不小心破坏系统/内存/硬件资源;
  • 封装性:用户程序不需要实现更加底层的代码;
  • 利于调度:如果多个用户程序都在等待键盘输入,这时就需要进行调度;统一交给操作系统调度更加方便。

10. 产生死锁的原因?

由于系统中存在一些不可剥夺资源,而当两个或两个以上进程占有自身资源,并请求对方资源时,会导致每个进程都无法向前推进,这就是死锁。

竞争资源

例如:系统中只有一台打印机,可供进程 A 使用,假定 A 已占用了打印机,若 B 继续要求打印机打印将被阻塞。

系统中的资源可以分为两类:

  1. 可剥夺资源:是指某进程在获得该资源后,该资源可别其他进程或系统剥夺,CPU和主存均属于可剥夺资源。
  2. 不可剥夺资源:当系统把这类资源分配给某进程后,再不能强行收回,只能在进程用完后自行释放,如打印机等。

进程推进顺序不当

例如:进程 A 和 进程 B 互相等待对方的数据。

11. 死锁产生的必要条件

  1. 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
  2. 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
  1. 不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
  2. 环路等待条件:在发生死锁时,必然存在一个进程--资源的环形链。

12. 解决死锁的基本方法

  1. 预防死锁
  2. 避免死锁
  1. 检测死锁
  2. 解除死锁

13. 怎么预防死锁?

  1. 破坏互斥条件:把互斥的资源换为共享资源;
  2. 破坏不可剥夺条件:a. 当某进程获得了部分资源,但得不到其它资源,则释放已占有的资源;b. 当某进程请求已被占用的资源时,根据进程优先级判定是否可以获得资源;
  1. 破坏请求保持条件:在程序运行之前为所有的进程分配好资源,之后一直保持自己的资源;
  2. 破坏环路等待条件:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反。

14. 怎么避免死锁?

银行家算法

当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。

当进程在执行中继续申请资源时,先测试该进程已占用的资源数与本次申请资源数之和是否超过了该进程对资源的最大需求量。若超过则拒绝分配资源。若没超过则再测试系统现存的资源能否满足该进程尚需的最大资源量,若满足则按当前的申请量分配资源,否则也要推迟分配。

安全序列

是指系统能按某种进程推进顺序(P1, P2, P3, ..., Pn),为每个进程 Pi 分配其所需要的资源,直至满足每个进程对资源的最大需求,使每个进程都可以顺序地完成。这种推进顺序就叫安全序列【银行家算法的核心就是找到一个安全序列】

系统安全状态

如果系统能找到一个安全序列,就称系统处于安全状态,否则,就称系统处于不安全状态。

15. 怎么解除死锁?

  1. 资源剥夺:挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他死锁进程(但应该防止被挂起的进程长时间得不到资源);
  2. 撤销进程:强制撤销部分、甚至全部死锁进程并剥夺这些进程的资源(撤销的原则可以按进程优先级和撤销进程代价的高低进行);
  1. 进程回退:让一个或多个进程回退到足以避免死锁的地步。进程回退时自愿释放资源而不是被剥夺。要求系统保持进程的历史信息,设置还原点。

内存管理

16. 什么是缓冲区溢出?有什么危害?

缓冲区为暂时置放输出或输入资料的内存。

缓冲区溢出是指当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。造成缓冲区溢出的主要原因是程序中没有仔细检查用户输入是否合理。

计算机中,缓冲区溢出会造成的危害主要有以下两点:程序崩溃导致拒绝服务 和 跳转并且执行一段恶意代码。

17. 内存管理方式有哪些

简单分为连续分配管理方式和非连续分配管理方式这两种。连续分配管理方式是指为一个用户程序分配一个连续的内存空间,常见的如 块式管理 。同样地,非连续分配管理方式允许一个程序使用的内存分布在离散或者说不相邻的内存中,常见的如页式管理 和 段式管理。

  1. 块式管理 :远古时代的计算机操系统的内存管理方式。将内存分为几个固定大小的块,每个块中只包含一个进程。如果程序运行需要内存的话,操作系统就分配给它一块,如果程序运行只需要很小的空间的话,分配的这块内存很大一部分几乎被浪费了。这些在每个块中未被利用的空间,我们称之为碎片。
  2. 页式管理 :把主存分为大小相等且固定的一页一页的形式,页较小,相对相比于块式管理的划分力度更大,提高了内存利用率,减少了碎片。页式管理通过页表对应逻辑地址和物理地址。
  1. 段式管理 :页式管理虽然提高了内存利用率,但是页式管理其中的页实际并无任何实际意义。段式管理把主存分为一段段的,每一段的空间又要比一页的空间小很多 。但是,最重要的是段是有实际意义的,每个段定义了一组逻辑信息,例如,有主程序段 MAIN、子程序段 X、数据段 D 及栈段 S 等。段式管理通过段表对应逻辑地址和物理地址。
  2. 段页式管理:段页式管理机制结合了段式管理和页式管理的优点。简单来说段页式管理机制就是把主存先分成若干段,每个段又分成若干页,也就是说 段页式管理机制 中段与段之间以及段的内部的都是离散的。

18. 局部性原理

  • 时间上:最近被访问的页在不久的将来还会被访问;
  • 空间上:内存中被访问的页周围的页也很可能被访问。

18. 快表和多级页表

在分页内存管理中,很重要的两点是:

  1. 虚拟地址到物理地址的转换要快。
  2. 解决虚拟地址空间大,页表也会很大的问题

快表

为了解决虚拟地址到物理地址的转换速度,操作系统在 页表方案 基础之上引入了 快表 来加速虚拟地址到物理地址的转换。我们可以把快表理解为一种特殊的高速缓冲存储器(Cache),其中的内容是页表的一部分或者全部内容。作为页表的Cache,它的作用与页表相似,但是提高了访问速率。由于采用页表做地址转换,读写内存数据时CPU要访问两次主存。有了快表,有时只要访问一次高速缓冲存储器,一次主存,这样可加速查找并提高指令执行速度。

使用快表之后的地址转换流程是这样的:

  1. 根据虚拟地址中的页号查快表;
  2. 如果该页在快表中,直接从快表中读取相应的物理地址;
  1. 如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中;
  2. 当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一个页。

看完了之后你会发现快表和我们平时经常在我们开发的系统使用的缓存(比如 Redis)很像,的确是这样的,操作系统中的很多思想、很多经典的算法,你都可以在我们日常开发使用的各种工具或者框架中找到它们的影子。

多级页表

引入多级页表的主要目的是为了避免把全部页表一直放在内存中占用过多空间,特别是那些根本就不需要的页表就不需要保留在内存中。多级页表属于时间换空间的典型场景,具体可以查看下面这篇文章

总结

为了提高内存的空间性能,提出了多级页表的概念;但是提到空间性能是以浪费时间性能为基础的,因此为了补充损失的时间性能,提出了快表(即TLB)的概念。不论是快表还是多级页表实际上都利用到了程序的局部性原理,局部性原理在后面的虚拟内存这部分会介绍到。

17. 分页和分段的区别

  1. 段是信息的逻辑单位,它是根据用户的需要划分的,因此段对用户是可见的 ;页是信息的物理单位,是为了管理主存的方便而划分的,对用户是透明的;
  2. 段的大小不固定,有它所完成的功能决定;页大大小固定,由系统决定;
  1. 段向用户提供二维地址空间;页向用户提供的是一维地址空间;
  2. 段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制。

18. 物理地址、逻辑地址、虚拟内存的概念

  1. 物理地址:它是地址转换的最终地址,进程在运行时执行指令和访问数据最后都要通过物理地址从主存中存取,是内存单元真正的地址。
  2. 逻辑地址:是指计算机用户看到的地址。例如:当创建一个长度为 100 的整型数组时,操作系统返回一个逻辑上的连续空间:指针指向数组第一个元素的内存地址。由于整型元素的大小为 4 个字节,故第二个元素的地址时起始地址加 4,以此类推。事实上,逻辑地址并不一定是元素存储的真实地址,即数组元素的物理地址(在内存条中所处的位置),并非是连续的,只是操作系统通过地址映射,将逻辑地址映射成连续的,这样更符合人们的直观思维。
  1. 虚拟内存:是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。每个程序都拥有自己的地址空间,这个地址空间被分成大小相等的页,这些页被映射到物理内存;但不需要所有的页都在物理内存中,当程序引用到不在物理内存中的页时,由操作系统将缺失的部分装入物理内存。这样,对于程序来说,逻辑上似乎有很大的内存空间,只是实际上有一部分是存储在磁盘上,因此叫做虚拟内存。

虚拟内存的优点是让程序可以获得更多的可用内存。

19. CPU寻址,为什么需要虚拟地址空间?

现代处理器使用的是一种称为 虚拟寻址(Virtual Addressing) 的寻址方式。使用虚拟寻址,CPU需要将虚拟地址翻译成物理地址,这样才能访问到真实的物理内存。 实际上完成虚拟地址转换为物理地址转换的硬件是 CPU 中含有一个被称为 内存管理单元(Memory Management Unit, MMU)的硬件。如下图所示:

为什么要有虚拟地址空间呢?

先从没有虚拟地址空间的时候说起吧!没有虚拟地址空间的时候,程序都是直接访问和操作的都是物理内存 。但是这样有什么问题呢?

  1. 用户程序可以访问任意内存,寻址内存的每个字节,这样就很容易(有意或者无意)破坏操作系统,造成操作系统崩溃。
  2. 想要同时运行多个程序特别困难,比如你想同时运行一个微信和一个QQ音乐都不行。为什么呢?举个简单的例子:微信在运行的时候给内存地址1xxx赋值后,QQ音乐也同样给内存地址1xxx赋值,那么QQ音乐对内存的赋值就会覆盖微信之前所赋的值,这就造成了微信这个程序就会崩溃。

总结来说:如果直接把物理地址暴露出来的话会带来严重问题,比如可能对操作系统造成伤害以及给同时运行多个程序造成困难。

通过虚拟地址访问内存有以下优势:

  • 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区。
  • 程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,内存管理器会将物理内存页(通常大小为 4 KB)保存到磁盘文件。数据或代码页会根据需要在物理内存与磁盘之间移动。
  • 不同进程使用的虚拟地址彼此隔离。一个进程中的代码无法更改正在由另一进程或操作系统使用的物理内存。

19. 页面置换算法有哪些?

地址映射过程中,若在页面中发现所要访问的页面不在内存中,则发生缺页中断 。

当发生缺页中断时,如果当前内存中并没有空闲的页面,操作系统就必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。用来选择淘汰哪一页的规则叫做页面置换算法,我们可以把页面置换算法看成是淘汰页面的规则。

请求调页,也称按需调页,即对不在内存中的“页”,当进程执行时要用时才调入,否则有可能到程序结束时也不会调入。而内存中给页面留的位置是有限的,在内存中以帧为单位放置页面。为了防止请求调页的过程出现过多的内存页面错误(即需要的页面当前不在内存中,需要从硬盘中读数据,也即需要做页面的替换)而使得程序执行效率下降,我们需要设计一些页面置换算法,页面按照这些算法进行相互替换时,可以尽量达到较低的错误率。常用的页面置换算法如下:

  • 时钟(Clock)置换算法
    时钟置换算法也叫最近未用算法 NRU(Not RecentlyUsed)。该算法为每个页面设置一位访问位,将内存中的所有页面都通过链接指针链成一个循环队列。
  • OPT页面置换算法(最佳页面置换算法) :理想情况,不可能实现,一般作为衡量其他置换算法的方法。

选未来最远将使用的页淘汰,是一种最优的方案,可以证明缺页数最小

  • FIFO页面置换算法(先进先出页面置换算法)  : 总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰。
  • LRU页面置换算法(最近未使用页面置换算法) :LRU(Least Currently Used)算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间T,当须淘汰一个页面时,选择现有页面中其T值最大的,即最近最久未使用的页面予以淘汰。
  • LFU页面置换算法(最少使用页面排序算法) : LFU(Least Frequently Used)算法会让系统维护一个按最近一次访问时间排序的页面链表,链表首节点是最近刚刚使用过的页面,链表尾节点是最久未使用的页面。访问内存时,找到相应页面,并把它移到链表之首。缺页时,置换链表尾节点的页面。也就是说内存内使用越频繁的页面,被保留的时间也相对越长。

什么是颠簸现象

颠簸本质上是指频繁的页调度行为。进程发生缺页中断时必须置换某一页。然而,其他所有的页都在使用,它置换一个页,但又立刻再次需要这个页。因此会不断产生缺页中断,导致整个系统的效率急剧下降,这种现象称为颠簸。内存颠簸的解决策略包括:

  • 修改页面置换算法;
  • 降低同时运行的程序的数量;
  • 终止该进程或增加物理内存容量。

20. 谈谈你对动态链接库和静态链接库的理解?

静态链接就是在编译链接时直接将需要的执行代码拷贝到调用处,优点就是在程序发布的时候就不需要的依赖库,也就是不再需要带着库一块发布,程序可以独立执行,但是体积可能会相对大一些。

动态链接就是在编译的时候不直接拷贝可执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中,然后程序在运行到指定的代码时,去共享执行内存中已经加载的动态库可执行代码,最终达到运行时连接的目的。优点是多个程序可以共享同一段代码,而不需要在磁盘上存储多个拷贝,缺点是由于是运行时加载,可能会影响程序的前期执行性能。

21. 零拷贝

零拷贝(Zero-copy)技术指在计算机执行操作时,CPU 不需要先将数据从一个内存区域复制到另一个内存区域,从而可以减少上下文切换以及 CPU 的拷贝时间。它的作用是在数据报从网络设备到用户程序空间传递的过程中,减少数据拷贝次数,减少系统调用,实现 CPU 的零参与,彻底消除 CPU 在这方面的负载。实现零拷贝用到的最主要技术是 DMA 数据传输技术和内存区域映射技术。

  • 零拷贝机制可以减少数据在内核缓冲区和用户进程缓冲区之间反复的 I/O 拷贝操作。
  • 零拷贝机制可以减少用户进程地址空间和内核地址空间之间因为上下文切换而带来的 CPU 开销。

在 Linux 中零拷贝技术主要有 3 个实现思路:用户态直接 I/O、减少数据拷贝次数以及写时复制技术。

  • 用户态直接 I/O:应用程序可以直接访问硬件存储,操作系统内核只是辅助数据传输。这种方式依旧存在用户空间和内核空间的上下文切换,硬件上的数据直接拷贝至了用户空间,不经过内核空间。因此,直接 I/O 不存在内核空间缓冲区和用户空间缓冲区之间的数据拷贝。
  • 减少数据拷贝次数:在数据传输过程中,避免数据在用户空间缓冲区和系统内核空间缓冲区之间的CPU拷贝,以及数据在系统内核空间内的CPU拷贝,这也是当前主流零拷贝技术的实现思路。
  • 写时复制技术:写时复制指的是当多个进程共享同一块数据时,如果其中一个进程需要对这份数据进行修改,那么将其拷贝到自己的进程地址空间中,如果只是数据读取操作则不需要进行拷贝操作。

22. 协程机制

  • 依附于线程的内存模型,切换开销小
  • 遇到阻塞即归还执行权,代码同步
  • 无需加锁
  • 协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
  1. 一个线程可以拥有多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。
  2. 线程进程都是同步机制,而协程则是异步
  1. 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

设备管理

磁盘调度算法

读写一个磁盘块的时间的影响因素有:

  • 旋转时间(主轴转动盘面,使得磁头移动到适当的扇区上)
  • 寻道时间(制动手臂移动,使得磁头移动到适当的磁道上)
  • 实际的数据传输时间

其中,寻道时间最长,因此磁盘调度的主要目标是使磁盘的平均寻道时间最短。

#1. 先来先服务

FCFS, First Come First Served

按照磁盘请求的顺序进行调度。

优点是公平和简单。缺点也很明显,因为未对寻道做任何优化,使平均寻道时间可能较长。

#2. 最短寻道时间优先

SSTF, Shortest Seek Time First

优先调度与当前磁头所在磁道距离最近的磁道。

虽然平均寻道时间比较低,但是不够公平。如果新到达的磁道请求总是比一个在等待的磁道请求近,那么在等待的磁道请求会一直等待下去,也就是出现饥饿现象。具体来说,两端的磁道请求更容易出现饥饿现象。

#3. 电梯算法

SCAN

电梯总是保持一个方向运行,直到该方向没有请求为止,然后改变运行方向。

电梯算法(扫描算法)和电梯的运行过程类似,总是按一个方向来进行磁盘调度,直到该方向上没有未完成的磁盘请求,然后改变方向。

因为考虑了移动方向,因此所有的磁盘请求都会被满足,解决了 SSTF 的饥饿问题。

文件管理

10. 什么是文件?

文件(Files)是由进程创建的逻辑信息单元。一个磁盘会包含几千甚至几百万个文件,每个文件是独立于其他文件的。事实上,如果你能把每个文件都看作一个独立的地址空间,那么你就可以真正理解文件的概念了。进程能够读取已经存在的文件,并在需要时重新创建他们。存储在文件中的信息必须是持久的,这也就是说,不会因为进程的创建和终止而受影响。一个文件只能在当用户明确删除的时候才能消失。

文件由操作系统进行管理,有关文件的构造、命名、访问、使用、保护、实现和管理方式都是操作系统设计的主要内容。从总体上看,操作系统中处理文件的部分称为 文件系统(file system)

文件系统https://mp.weixin.qq.com/s?__biz=MzUxODAzNDg4NQ==&mid=2247485446&idx=1&sn=2c525f008622b98bc08a66f2b4dcfee8&chksm=f98e4caccef9c5bafe0a69378623049a1cf37fbb8b61b65922f772e2170f98292b914a4268e5&scene=132#wechat_redirect

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值