ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

操作系统第2章进程与线程:核心考点、高频误区与得分点详解

操作系统第2章进程与线程:核心考点、高频误区与得分点详解 期末复习也好考研冲刺也好操作系统第2章“进程与线程”基本是整门课的命脉。这一章如果吃透了后续的内存管理、文件系统甚至设备管理学起来都会顺很多反之如果连进程和线程的关系、PCB里装了什么、信号量P/V操作解决什么问题都含糊后面的课基本上就是听天书。这篇我把第2章的核心考点、容易踩的坑、以及答题时的得分点全部捋一遍结合这些年帮学弟学妹划重点和批改作业时看到的高频误区尽量讲得直白一点希望能帮你从“背概念”提升到“真理解”。为什么这一章值得花大力气因为进程与线程不只是抽象概念它是整个操作系统的骨架。你之后学到的死锁、调度、IPC全部是建立在这一章的模型之上的。与其考前突击背几十个名词解释不如先把这一章的逻辑链条打通。1. 先建立整体框架进程是什么为什么要有线程很多人一上来就背“进程是资源分配的基本单位线程是CPU调度的基本单位”这句话虽然考试爱考但如果你只背这句话而不理解背后的动机做题的时候照样懵。我先从“为什么需要进程”这个问题切入把这章的逻辑主线理清楚。1.1 从“程序”到“进程”的跃迁为什么不用程序直接跑早期的操作系统比如单道批处理系统里内存中一次只放一个程序CPU运行完一个再去加载下一个。这种方式的问题在于一个程序在等待I/O的时候CPU只能干等着利用率极低。后来人们想到让多个程序同时驻留内存一个在等I/O时另一个去占用CPU这就是多道程序设计。多道程序并发执行之后问题来了多个程序共享CPU和内存操作系统靠什么来区分“哪个程序用到了哪块内存”“这个程序执行到哪条指令了”“它占用了哪些资源”光靠程序本身的代码和数据是不够的因为程序是静态的、躺在磁盘上的东西它自己没有“执行现场”的概念。所以操作系统为每个运行中的程序维护一个数据结构记录它的执行状态、寄存器值、内存边界、打开的文件等信息这个数据结构就是PCBProcess Control Block进程控制块。进程 程序 数据 PCB。你可以把PCB想象成每个进程的“身份证档案袋”操作系统想了解任何一个进程的情况只需要翻它的PCB即可。1.2 PCB里到底装了哪些东西考试常考填空题PCB的内容大致可以分成四类考试特别喜欢让你列举进程标识符PID唯一标识一个进程有进程号、父进程号PPID等。处理机状态信息通用寄存器、程序计数器PC、程序状态字PSW、栈指针等这些是进程被切换出去时需要在PCB里保存的现场下次调度回来时恢复。进程调度信息进程状态就绪/运行/阻塞、优先级、阻塞原因等。资源清单内存地址空间代码段/数据段/堆栈的边界、打开的文件列表、I/O设备使用情况等。这里需要特别指出的是操作系统内核在创建进程时会为进程分配独立的地址空间包括代码段、数据段、堆和栈。多个进程的地址空间是相互隔离的这也是“进程是资源分配的基本单位”这句话的真正含义——资源分配的最小粒度是进程不是线程。1.3 引入线程的动机进程的“重量”成了负担进程解决了多道程序并发的问题但进程本身太重了。进程在创建和销毁时要分配/回收独立地址空间开销很大进程之间切换时要切换整个地址空间涉及页表切换、TLB失效等开销同样很大。而且在同一个应用内部经常有多个任务需要并发执行并共享数据如果全部用独立进程实现IPC进程间通信的开销会非常大。于是线程被引入。线程是进程内部的一条执行流一个进程可以包含多个线程这些线程共享进程的地址空间、打开的文件、全局变量等资源每个线程只需要保留自己的线程ID、程序计数器、寄存器集合、栈。线程切换不涉及地址空间的切换所以比进程切换轻量得多。一句话总结进程和线程的关系进程是资源分配单位线程是CPU调度单位。进程是“容器”线程是“容器里干活的工人”。你要启动一个应用必须创建进程然后至少有一个“主线程”在跑你也可以在主线程里继续创建多个子线程来并行干活。2. 进程状态转换一张图搞定但别只会画图进程状态和状态转换是每年的必考内容常见的考法是给你一个场景判断题比如“进程在等待打印机输出时它处于什么状态”答案是阻塞态。这个知识点不难但很多同学会在细节上丢分。2.1 三态模型与五态模型的对应关系经典的三态模型是运行态Running、就绪态Ready、阻塞态Blocked/Waiting。五态模型则是在三态基础上增加了“创建态New”和“终止态Terminated”。创建态进程正在被创建操作系统正在分配资源、初始化PCB此时进程还没进入就绪队列。就绪态进程已经准备好只等CPU。就绪队列里可以有多个进程CPU同一时刻只能运行一个。运行态进程正在CPU上执行。在单核CPU下任何时刻至多只有一个进程处于运行态。阻塞态进程因等待某事件如I/O完成、信号量、锁而无法继续执行即使给它CPU也没用。终止态进程执行结束或发生异常被撤销PCB将被回收。五态模型里最关键的转换关系有四个也是常考选择题的点就绪态 → 运行态被调度程序选中获得CPU。运行态 → 就绪态时间片用完或CPU被更高优先级进程抢占。运行态 → 阻塞态进程主动请求等待某事件比如调用read()读磁盘、申请锁失败注意这里一定是主动的。阻塞态 → 就绪态等待的事件完成后进程被唤醒回到就绪队列而不是直接运行。这里有个高频丢分点很多同学以为“阻塞态的事件完成后进程应该立刻继续运行”这是不对的。阻塞态唤醒后必须先回到就绪态等调度程序重新分配CPU。因为CPU可能正在被别人占用你不能直接把正在运行的进程踢下去除非有抢占机制且你优先级更高。2.2 为什么不能直接从阻塞态到运行态我再把这个逻辑拆细一点。想象你去医院挂号排队就绪队列是“候诊区”CPU是“诊室”。你因为某项检查没做完比如血常规结果还没出而离开候诊区去旁边椅子上等着这就是阻塞。检查结果出来之后护士会让你回到候诊区继续排队而不是直接把你推进诊室——因为诊室里可能已经有别的病人在看病了。所以“阻塞态 → 就绪态 → 运行态”的路径是必须的。2.3 挂起态七态模型简单了解一下有些教材在五态模型之上还会讲“挂起Suspend”状态。挂起的本质是进程被移到外存磁盘交换区暂时不参与调度。常见触发原因包括系统内存不足、用户手动挂起、父进程暂停子进程等。挂起态与阻塞态的区别在于阻塞是“等待某事件”挂起是“被挪走存放”。这块一般院校的期末考考得不多但如果你们老师讲了要记住挂起态下的进程不占用内存被挂起的进程即使其等待的事件发生了也不能直接运行必须先激活换入内存回到就绪态。3. 进程与线程的区别除了“资源/调度”之外还要会答这些“进程与线程的区别”属于期末必考简答题。除了那句“进程是资源分配单位线程是CPU调度单位”之外我建议你把对比维度记全考试时按维度分条作答得分率更高。对比维度进程线程资源拥有独立的地址空间、文件、I/O等资源共享所属进程的资源只有独立的栈和少量私有存储调度进程是资源分配单位线程是调度单位现代OS中进程不再被直接调度线程是CPU调度和分派的基本单位开销创建/销毁/切换开销大涉及地址空间切换创建/销毁/切换开销小不需要切换地址空间通信进程间通信IPC需要借助系统机制管道、消息队列、共享内存等线程间通信可以直接读写共享内存变量但要处理互斥健壮性一个进程崩溃一般不影响其他进程一个线程崩溃比如野指针写坏共享内存可能导致整个进程崩溃系统并发多个进程可以分布在多核处理器上并行同一进程内的多个线程也可分配到多核并行如果能并行调度这里有几个考试时的加分点第一进程切换开销远大于线程切换原因要写清楚“进程切换需要切换地址空间导致页表切换和TLB快表失效而线程切换只切换寄存器上下文和栈指针”。有同学只写“进程开销大”而不写“为什么大”简答题只能拿到一半分。第二创建进程和创建线程的开销对比要会解释。创建进程需要分配独立的内存空间、建立页表、初始化PCB这些都是内核态操作很重。创建线程只需要在进程已有地址空间里分配一块栈空间再做一个线程控制块TCB轻量得多。Linux下fork一个进程和pthread_create创建一个线程性能差距能到数量级。第三关于“一个进程崩溃不影响其他进程”这个特性在面试和期末考中都很重要。操作系统在创建进程时做了地址空间隔离一个进程访问越界只会触发自己进程的段错误/非法访问异常内核会终止这个进程而不会牵连其他进程。这也是为什么浏览器、大型服务器喜欢用多进程而不是多线程来隔离故障域比如Chrome的每个标签页是一个进程。但线程就不一样了。同一个进程里的线程共用一份地址空间如果线程A往随机地址写数据可能把线程B正在使用的栈或堆弄坏或者把文件描述符表弄乱整个进程崩溃。所以多线程程序要特别注意线程安全也就是“线程互斥”的由来。4. 线程的实现模型与协程用户级、内核级与混合线程模型是很多同学容易忽略的考点但这几年高校特别喜欢考。其实三类模型的区别很清晰关键在于“线程的创建、调度、切换由谁来做”。4.1 用户级线程ULTUser-Level Thread线程的管理完全在用户空间完成内核根本不知道线程的存在。线程库比如早期的GNU Pthreads在用户态通过运行时系统来创建、调度线程。内核看到的仍然只是一个进程单线程调度单位依然是进程。用户级线程的优点是切换不需要陷入内核态非常快缺点是如果进程内一个线程执行系统调用比如read发生阻塞整个进程的所有线程都会被阻塞因为内核只认识这个进程它不会去调度进程内的其他线程。此外在多核CPU上用户级线程无法被分配到不同核心上并行执行因为内核把它当成一个调度实体。4.2 内核级线程KLTKernel-Level Thread线程的管理全部由内核完成线程的创建、调度、切换都由内核负责现代Linux使用的就是内核级线程模型。每个用户线程对应一个内核线程或者更准确地说用户进程直接使用内核线程来执行。优点多核并行没问题一个线程阻塞不影响同进程的其他线程内核会调度其他线程缺点是线程切换要陷入内核态开销比用户级线程大每次切换都要通过系统调用。4.3 混合模型多对多模型用户级线程和内核级线程不是一一对应的而是多个用户级线程映射到较少数量的内核级线程上。既避免了用户级线程“一阻塞全阻塞”的问题又能控制内核线程数量降低切换开销。Linux的NPTLNative POSIX Thread Library实现中实际采用的是“一对一”模型但在设计思想上借鉴了混合模型的优点。4.4 协程与线程到底差在哪里热搜词里有一个“计算机操作系统管程和协程”这个值得多说一句。协程Coroutine不是操作系统里的概念而是用户态的、由语言运行时或用户代码自己调度的轻量级执行流。它的切换完全在用户空间完成不涉及内核上下文切换因此比线程还轻。协程的关键特点是协作式调度执行流主动让出yield而不是被系统抢占。线程则通常是抢占式调度由内核决定何时切换。协程适合处理I/O密集型的并发场景比如高并发的网络请求在一个线程内部用事件循环驱动多个协程交替执行不需要创建成千上万个内核线程。比如Go语言的goroutine就是协程的典型代表当然说它是“协程调度器”更准确Python的async/await也是协程机制。期末如果考“进程、线程、协程”对比答题重点可以放在“调度主体”和“切换开销”上进程和线程的调度主体是操作系统内核协程的调度主体是用户程序或运行时切换开销方面进程 线程 协程并行能力方面进程和内核级线程可以并行利用多核协程在单线程内是并发的除非配合多线程。5. 处理器调度不只是“先来先服务”背公式就行进程与线程章节里处理机调度算法也是必考内容。常见的算法有FCFS、SJF/SRTF、优先级调度、时间片轮转RR、多级反馈队列MLFQ。期末题里给一组进程的到达时间和服务时间让你算等待时间、周转时间、平均周转时间这种题其实是送分题但很多同学因为“没掌握好时间轴上的推进方式”而做错。5.1 五种经典调度算法速记先来先服务FCFS按照进程到达就绪队列的顺序排队执行非抢占。优点是公平、实现简单缺点是短进程可能被长进程阻塞护航效应。例题里算平均等待时间时直接按到达顺序推进即可。有一点要注意如果进程是在执行过程中陆续到达的要按时间轴排列而不是单纯按序号排。短作业优先SJF非抢占式每次从就绪队列中选择预计运行时间最短的进程。SJF能给出最小的平均等待时间前提是你知道未来的CPU区间长度实际系统中只能估算所以它是理论上的“最优”调度标准但实际中很难精确预知。最短剩余时间优先SRTFSJF的抢占版本。当一个新进程到达且其剩余时间比当前运行进程的剩余时间还短时CPU切换到新进程。算这道题的时候关键在于每到一个“新进程到达事件”时要比较“当前进程剩余时间”和“新进程需要的CPU时间”谁小谁运行。时间片轮转RR每个进程只能连续执行一个时间片如20ms时间片用完则回到就绪队列队尾。重点时间片大小的选择很关键——时间片太小上下文切换开销占比太高时间片太大退化为FCFS。答题时要注意新到达进程插入就绪队列的位置通常放在队尾如果时间片结束和进程到达发生在同一时刻不同教材处理方式可能不同你按自己老师讲的来做。多级反馈队列MLFQ设置多个不同优先级的就绪队列新进程进入最高优先级队列同一队列内按时间片轮转调度当进程时间片用完但未完成则降到下一级队列。高优先级队列先执行且高优先级队列为空时才执行低优先级。这个算法的精髓是I/O密集型进程和短进程能很快完成长计算型进程自动沉底。5.2 调度算法的考点延伸什么场景选什么算法期末简答题如果问“某系统适合用哪种调度算法”一般从这几个维度回答交互式系统比如分时系统、桌面操作系统需要响应快适合时间片轮转或多级反馈队列。批处理系统对平均周转时间敏感可用SJF或SRTF。实时系统需要满足截止时间用EDF最早截止时间优先或固定优先级抢占调度。答题时要先分析场景特点再给出算法选择最后说明原因。比如“多级反馈队列综合了RR的响应快和SJF的短作业优先优点因此通用操作系统如Linux、Windows调度器多采用它或其变体”。6. 同步与互斥信号量、管程与经典同步问题这章最抽象、也是考试大题的重灾区就是进程同步与互斥。说它抽象是因为一个“只有两个操作的系统调用原语”能折腾出各种花活。但只要抓住一个核心思路——用信号量里的计数器表达资源数量用Pwait、Vsignal操作实现资源的申请与释放——基本就能应付期末卷子了。6.1 临界区与四大原则并发进程共享数据时必须保证同一时刻只有一个进程进入临界区Critical Section访问共享资源。为了管理临界区必须满足四个条件忙则等待已有进程在临界区时其他进程必须等待。空闲让进临界区空闲且无进程申请时直接允许进入或者说当无进程在临界区时允许一个申请者进入。有限等待等待进程不能无限等下去必须在有限时间内进入临界区。让权等待当进程不能进入临界区时应立即释放CPU防止忙等待。这一点经常被忽略。用代码实现临界区时有软件方法Peterson算法和硬件方法关中断、TS指令、CAS期末一般只考概念但Peterson算法偶尔会出现在选择题里两个进程互相让出CPU导致谁都无法进入临界区活锁就是一个经典陷阱。6.2 信号量的P/V操作到底在干什么信号量S是一个整数变量表示可用资源数量。P操作wait在旧教材里叫down就是对S的原子减一如果S0则进程阻塞V操作signal旧教材叫up是对S的原子加一如果S0则唤醒一个阻塞进程。关于P/V操作初学者最容易卡在两个地方第一为什么P/V是原子操作。因为如果不原子两个进程同时做S--时就会互相覆盖。信号量的P/V操作是操作系统提供的原语底层靠关中断或TS指令保证原子性这一点考试常考填空题。第二信号量的初始值怎么定。互斥信号量mutex初始值为1表示一把锁同步信号量初始值一般设为0表示事件还没发生或n表示资源数量。定义信号量的本质是“你要保护几个资源就把它初始化为几”。6.3 经典同步问题生产者-消费者、读者-写者、哲学家进餐这三个问题往年考的频率非常高但老师会变着法子考不信你直接背模板就行。我按“解题思路”给你分析一次。生产者-消费者问题一个有限缓冲区生产者和消费者共享它。需要三个信号量mutex保护缓冲区互斥初值1、empty空缓冲区数量初值n、full满缓冲区数量初值0。生产者在向缓冲区放数据前先P(empty)再P(mutex)放完后V(mutex)再V(full)消费者先P(full)再P(mutex)取完后V(mutex)再V(empty)。这里有一个非常容易踩的坑P操作的顺序不能反。如果生产者先P(mutex)再P(empty)当缓冲区满时生产者持锁等待empty消费者想P(mutex)进入缓冲区取数据却拿不到锁于是死锁。所以一定要记住在进入临界区之前先申请同步信号量empty/full再申请互斥锁。读者-写者问题多个读者可以同时读写者和任何其他读者/写者互斥。需要两个信号量rw_mutex保护读写互斥初值1和count_mutex保护读者计数器初值1再加一个整数read_count记录当前读者数量。读者进入前先P(count_mutex)更新read_count当自己是第一个读者时P(rw_mutex)锁住写者退出时当自己是最后一个读者时V(rw_mutex)。这里体现的核心思想是第一个读者负责锁门最后一个读者负责开门。如果把“写者优先”加上即写者到达后阻止新读者进入避免写者被不断到达的读者饿死一般用额外的w_mutex信号量来实现比较复杂期末最多作为加分题出现。哲学家进餐问题5个哲学家围坐一桌每人需要左右两只筷子才能进餐。如果每个哲学家都先拿左边的筷子就会全部持有左筷等待右筷形成死锁。解决方案通常有三种最多允许4个哲学家同时拿筷子用count信号量兜底。使用AND型信号量一次申请两只筷子不过一般教材不讲实现。奇偶编号哲学家拿筷顺序不同奇数的先拿左再拿右偶数的先拿右再拿左。期末如果让你写哲学家进餐的伪代码推荐用“同时申请两根筷子”的思路或者限制最多4人同时持筷这两种最容易写对。6.4 管程比信号量更好用的高级同步机制管程Monitor是一个封装了共享变量和访问这些变量的过程的模块在Java里直接对应synchronized关键字和wait/notify机制。管程的核心特性是同一时刻只允许一个进程进入管程访问共享资源这叫互斥如果进程在管程内因条件不满足而等待要使用条件变量condition variable上的wait操作释放管程使用权等待其他进程signal唤醒。管程相比信号量的优势在于信号量要求程序员自己保证P/V的顺序和配对写错就容易死锁而管程把互斥封装在语言/运行时层面程序员只需要判断条件是否满足不需要手动加锁解锁。所以8、90年代以后的编程语言中管程模型比如JUC的LockCondition、Go的MutexCond比裸信号量更常见。期末如果考管程和信号量的对比答题点就是管程自动实现互斥、错误更难发生、条件变量使等待语义更清晰信号量灵活但易错。另外Java的synchronizedwait/notify就是管程的应用GVT管程的概念可以结合面向对象语言理解。7. 死锁四个必要条件和破解手段死锁也是期末大题高发区。死锁的定义是一组进程中的每个进程都在等待一个事件而该事件只能由这组进程中的其他进程触发导致大家都无法推进。7.1 四个必要条件一定要答全死锁产生的四个必要条件Coffman条件缺一不可答题时最好先各写一句定义再举例互斥条件Mutual Exclusion资源是非共享的同一时刻只能被一个进程占用。持有并等待Hold and Wait进程已经占有了至少一个资源又在等待获取其他资源。不可剥夺No Preemption进程已持有的资源不能被其他进程强行抢走只能由持有着自己释放。循环等待Circular Wait存在一个进程等待环路P0等P1的资源P1等P2的资源……Pn等P0的资源。对应地死锁的预防就是破坏这四个条件中的一个。比如要求进程在开始执行前一次性申请所有资源破坏持有并等待给资源编号、要求按序申请破坏循环等待允许抢夺资源破坏不可剥夺。7.2 死锁避免银行家算法银行家算法的本质是“判断系统在分配资源后是否仍然处于安全状态是否存在安全序列”。期末计算题如果考它千万别慌一步步来。算法步骤可以这样记忆系统里有m类资源n个进程。已知Available向量每类资源的剩余可用量、Max矩阵每个进程最多需要多少资源、Allocation矩阵每个进程当前已分配多少资源、Need矩阵Max减去Allocation。当进程P_i请求资源Request_i时先检查Request_i Need_i再检查Request_i Available然后做“试探性分配”。分配后运行安全性检查算法用一个Work向量初始等于Available和一个Finish数组初始全False每次找一个满足“FinishFalse且Need_i Work”的进程假设它执行完并归还资源Work Allocation_i标记FinishTrue不断重复。如果能找到让所有进程FinishTrue的顺序说明系统安全可以分配否则回到分配前的状态阻塞该请求。这个方法看起来繁琐其实你只要按“找安全序列”的方式在草稿纸上推演一遍就行。小心一个隐藏陷阱检查是否满足需求时是拿Need和Work对比不是拿Max或者Allocation。7.3 死锁检测与解除了解即可如果系统不预防也不避免死锁就需要死锁检测。通过资源分配图判断是否存在循环等待。检测出死锁后常用的解除方法有撤销所有死锁进程、逐个撤销死锁进程直到系统恢复、剥夺资源等。期末如果出选择题问“哪种方法可以实现死锁检测”常见答案是资源分配图Resource Allocation Graph法。8. 进程间通信IPC五种方式都要会列举进程间通信IPC这一小节是简答题高频考点。一般来说重点掌握五种方式信号、管道、消息队列、共享内存、套接字。每一种要写出“是什么”“特点”“应用场景”三层。8.1 信号Signal信号是异步事件通知机制比如CtrlC发出的SIGINT、除零产生的SIGFPE。注意信号不仅能用于进程间通信也可以由内核发给进程。信号的发送过程是“提前注册处理函数”收到信号后进程会在某个安全点执行处理函数。考点常出一个选择题“信号是软件中断用于通知进程发生了异步事件。”8.2 管道Pipe管道是最古老的Unix IPC机制本质是内核里的一块环形缓冲区。匿名管道pipe用于父子进程或兄弟进程之间的通信单向传输要双向通信需要创建两根管道。命名管道FIFO以文件形式出现在文件系统中可以在任意两个进程之间通信。管道的特点是数据以字节流形式传输、遵循先进先出、没有消息边界。考试偶尔会问“管道容量有限写进程在管道满时会阻塞”——这就是“读写端阻塞”问题。8.3 消息队列Message Queue消息队列是以“消息”为单位传递数据的IPC方式每个消息有类型和正文。相比管道消息队列有如下优点有消息边界、支持随机读取按消息类型读取、可以多个进程同时对同一队列读写。消息队列在内核中维持一个链表结构进程通过向队列发送/接收消息实现通信。8.4 共享内存Shared Memory共享内存是效率最高的IPC方式多个进程把同一块物理内存映射到各自地址空间于是可以直接读写这块内存不需要内核参与数据拷贝。它的缺点是多个进程同时读写同一块内存时存在竞争条件必须配合信号量等同步机制使用。考试常考对比题“共享内存为什么比管道/消息队列快”答案是管道和消息队列的数据传递都要经过内核缓冲区做一次copy_from_user/copy_to_user而共享内存只需要建立映射后直接访问物理内存省去了两次拷贝。但共享内存需要程序员自己处理同步使用门槛更高。8.5 套接字Socket套接字最初用于网络通信但也支持本机进程间通信Unix Domain Socket。它是目前跨机器进程通信的主流方式基于TCP/UDP协议。这里只需要记住“它可以用于不同主机上的进程通信这是其他几种IPC方式做不到的”。期末简答题如果考“列举进程间通信方式并比较”建议画表对比传输单位字节流/消息、是否需要内核参与数据拷贝、是否能跨主机三个方面信息量远比干巴巴列名字强。9. 高频丢分点与复习策略哪些地方最容易踩坑最后聊点实际的。这一章期末丢分通常不是因为不会而是因为“答得不够准”或“踩了概念雷”。我总结了几个常见丢分场景你复习的时候要特别注意。9.1 概念混淆清单下面这组高频易混点考前一定要自查一遍“进程是程序的一次执行”与“程序是静态的”这是老生常谈但还是有人分不清。程序是磁盘上存储的指令集合进程是程序被装载到内存并运行的动态过程。一个程序可以对应多个进程比如同时开多个终端一个进程在其生命周期中也只会执行一个程序但可以通过exec替换程序镜像。“就绪态”和“阻塞态”的对象搞混就绪态说明进程“万事俱备只欠CPU”阻塞态说明进程“即使有CPU也无法推进必须等某事件”。考试给你场景判断状态时先问自己“它是在等CPU还是在等某个资源/事件”“线程切换开销小”不等于“不用切换上下文”线程切换仍然要保存和恢复寄存器集合和栈指针只是不需要切换地址空间。有些选择题故意设干扰项“线程切换不需要上下文切换”这句话是错的。“共享内存最快”不等于“适合所有场景”因为需要处理同步、生命周期管理等复杂问题小数据量的通信用管道/消息队列反而更安全。快是快但不是免费用。“信号量可以解决互斥”不等于“信号量本身保证互斥”信号量只是提供了一种机制如果程序员忘记写P/V或者顺序写反互斥照样被破坏。管程才有语言级的互斥保证。“用户级线程”和“内核级线程”不能只看表面数量早期操作系统中的线程实现多数为用户级线程比如旧版Java绿色线程现代操作系统Linux、Windows的线程都是内核级线程。9.2 怎么刷题效率最高期末复习刷题不要光背答案。我建议你按这样的顺序来第一步画体系图在A4纸上自己画一张思维导图从“进程”和“线程”两个中心节点发散把PCB、状态转换、调度算法、同步互斥、死锁、IPC全部串联起来。画完你能说出来“每个知识点的关键词是什么”就算过了第一关。第二步动手算计算题调度算法的等待时间/周转时间、银行家算法的安全序列、信号量P/V操作的并发执行结果这三大类题必须动笔在纸上算。尤其是银行家算法很多同学觉得看懂了就不练一到考场手生推演几步就卡住。第三步整理“为什么”针对每个知识点给自己出一道“为什么”题。比如为什么引入线程为什么阻塞唤醒后进就绪队列而不是直接运行为什么共享内存最快为什么P操作顺序反了会死锁能在不用翻书的情况下把这些为什么讲明白你的理解深度已经超过大多数人了。第四步限时做往年卷期末题目和考研题不太一样一般会更注重概念理解和简单计算但有些院校的期末难度也不低。找到你们学校近5年的期末试卷严格按照考试时间做一遍重点看有没有状态转换的选择题、信号量的大题、调度算法的计算题。9.3 一个说服自己“别裸考”的实例我之前带过一个学弟他复习第2章的时候进度条一直停留在“看过一遍书”然后说自己会了。我拿了一道经典生产者-消费者问题让他写代码他写了大概十五分钟还是把P操作顺序写反了直接死锁。后来我让他自己上机调把死锁现象跑出来之后他复盘了一句“原来书上说的死锁是真实会发生的不是概念骗我。”期末他考得还不错原因很简单——他不再满足于“读懂”代码而是亲手把错误复现代码写出来改对。这里不是说让你把每个算法都上机验证但对于信号量和死锁这类抽象内容在纸上画出进程状态变化图和资源分配图远比反复默念定义有用。这一章的内容确实多但它的逻辑主线很清晰为了多道并发需要进程进程太重于是引入线程多个进程/线程并发需要调度共享资源时需要同步互斥同步不当可能死锁进程之间要协作需要IPC。把这根主线记在心里所有知识点都是挂在这根线上的珠子你就不会觉得内容零散了。
返回列表