操作系统基础知识

操作系统基础知识

操作系统和CPU

CPU是一个执行指令的家伙,它里边有算法逻辑单元ALU,能够对二进制指令进行操作。起初我们把想要执行的东西写成一堆指令,让CPU按序执行就好了。

但现代程序太复杂了,有存储、驱动等各式各样的东西搭配使用,有时程序执行的时候卡死了,怎么办?这时候我们需要有一个第三方的“管家”,让他拥有控制权,来管理资源和运行的指令,它就是操作系统(Operator System)。这样一来,操作系统存在的意义就是如何高效调度(榨干)CPU。而CPU不仅执行内存中的程序指令,也包括操作系统本身的指令。

可以得到,OS运行在CPU之上,CPU来执行其所有的管理功能(如内存分配、I/O操作、权限检查等),当然也执行用户的程序代码。

操作系统还分内核态和用户态。当一个应用程序需要CPU执行一个特权操作(如访问文件、创建新进程)时,它执行操作系统提供的系统调用,而后操作系统接收到请求后,使用CPU以内核模式(Kernel Mode)执行这些特权操作。

线程和CPU

有了操作系统之后,为了能让CPU“同时”处理多任务,且程序执行互相不影响、隔离开来,便有了进程。进程是操作系统进行资源分配的最小单位。不过由于进程切换的开销太大了,且进程之间的通信效率很差劲,又引入了线程,线程是操作系统进行CPU调度的最小单位。

线程属于操作系统概念。

多线程和多CPU

为了真正的并行,现在处理器通常是多CPU的。只有一个操作系统内核在运行,管理多个线程和多CPU。一个线程在同一时刻只能由一个CPU核心执行,一个CPU可以在操作系统的调度下切换着执行不同线程代码。也就是说,操作系统可以在不同时刻将同一个线程迁移到不同的核心(例如,负载均衡、CPU亲和性),但不会在同一时刻由多个CPU同时执行同一个线程的代码片段。

线程调度和CPU

目前操作系统的权力是很大的,由操作系统做主导,来指挥协调各个线程上的程序在各个CPU上的执行。那么就涉及到线程调度问题——CPU该跑哪个线程的任务。目前主流抢占式调度算法是当线程时间片用完进行切换。可以得到,CPU时间片是分配给线程的

线程调度和CPU的关系是,当一个线程被操作系统调度到运行态,它就会占用一个CPU核心在其时间片内运行。如果有多个CPU核心,并且有多个可运行线程,那么可以同时有多个线程在多个核心上并行执行。

可以知道,当线程时间片耗尽,CPU的执行权会被新的线程抢占,以执行更高特权级的线程。这里就涉及到线程切换的细节了。

仔细思考一下,一般的指令都是在线程环境中执行的,那么,“线程时间片耗尽”,这个判断是在线程环境中执行吗?在当然线程执行吗?显然不可能,判断线程时间片这个操作肯定由外界来确定而不是线程它自身。那是在内核线程中执行吗?想想也不太可能,首先,判断时间片耗尽这个操作应该是经常发生的,如果都切换到内核线程判断,那太慢了;其次,这个内核线程也是个线程,也需要检查时间片才能运行。

线程调度抢占

基于时间片轮转的线程调度算法,在某个线程时间片耗尽,有抢占的环节,这个抢占是如何发生的?其实是通过硬件定时器的硬件中断来完成的。它是异步的、线程无关的。操作系统会配置好一个硬件计时器,间隔产生中断信号。每当一段时间的中断信号触发,CPU 暂停当前执行,跳转到内核预先设置好的计时器中断服务例程 (ISR) 的入口,它会调用调度器代码,调度器会检查当前线程的时间片,并执行线程切换的逻辑。

现在可以试着回答这个问题:

当线程时间片耗尽时,执行线程切换,这时触发一个硬件中断,停止当前线程执行,并切换到新的线程中执行。这个过程正确吗?

不正确。硬件的中断是由硬件计时器间隔发给CPU的,CPU响应了这个中断,并判断线程时间片是否耗尽。如果没耗尽,无事发生;如果耗尽了,执行线程切换的逻辑。可以得到,先有的硬件计时器中断判断是否耗尽时间片,再有的线程切换。

那么,无论什么时候,只要线程时间片用完了,就会触发线程抢占吗?

并非何时线程都可抢占

什么时候线程不可抢占呢?可以联想,线程调度的抢占,是通过计时器中断定时探测线程时间片是否用完来执行线程切换的,那么当CPU关闭中断时,CPU就没法收到时钟中断信号了,也就没法跳转到内核预先设置好的计时器中断服务例程入口调用调度器了。

设想这样的情形,操作系统内核代码为了保证死锁或者数据一致性,调用关中断指令关闭了一个CPU的中断,此时定时器触发中断来检查是否线程时间片用完,那么这个中断信号会丢失吗?不会。该中断信号不会丢失,而是被硬件“挂起(Pending)”了。中断处理程序会被“推迟(Delayed)”执行。

Q:编写用户程序代码需要考虑中断吗?

A:不需要。用户程序运行在较低的特权级别指令(Ring3),没有权限执行关中断这种特权指令。用户代码如果需要访问共享资源,应使用操作系统提供的标准同步机制,如互斥锁、信号量、条件变量等。

Q:处于临界区(持有锁)的线程可以被抢占吗?

A:完全可以。线程有没有处于临界区和CPU时间片用完导致的线程切换两者是独立的,操作系统调度器不关心线程是否持有锁。锁是用来保护数据的,而时间片是用来分配 CPU 执行权的,这两者是独立的机制。