(嵌入式八股)第5章 操作系统(四)(后续操作系统相关会持续补充在这里)

5.31 并发、同步、异步、互斥、阻塞、非阻塞的理解

并发(Concurrency)

并发是指多个任务或操作在同一时间段内进行。任务之间可以相互独立,并不一定按照严格的顺序执行。并发强调的是资源的时分复用,也就是说,多个任务共享一个处理器的时间片,每个任务在执行时会在不同时间片之间切换。

  • 并发的特点:任务之间是交替进行的。在同一个执行单元上,任务按时间片轮流执行。任务的执行顺序不一定固定,可以根据调度策略决定。并发可以通过多任务调度来实现,但不一定是同时执行。
  • 与串行的区别:串行:依次按照顺序完成每一件事,只有一个执行单元,任务一个接一个完成。并发:同一时段内,多个任务可以交替执行,即使在单核处理器上也可以通过时间片轮转模拟。
  • 与并行的区别:并行:指多个任务在同一时刻并排执行,通常需要多个执行单元(如多核处理器)。并行是并发的一种特例,所有任务在同一时刻都在执行,而不仅仅是交替执行。

同步(Synchronization)

同步是协调多个任务或操作之间的顺序和行为,以确保数据的一致性和操作的正确性。同步通常用于控制任务之间的依赖关系,确保某些操作按特定顺序执行。

  • 同步的特点:任务的执行顺序由程序或操作系统明确控制。任务可能会在某些点进行等待,直到前面的任务完成。主要用于防止竞争条件、数据不一致和死锁等问题。
  • 例子:多个线程对共享资源进行访问时,可能需要使用锁、信号量、条件变量等机制来进行同步。

异步(Asynchronous)

异步是指任务或操作在执行时,不必等待其他任务完成,可以独立执行。异步操作通常在后台执行,任务可以继续进行,而不需要被当前任务阻塞。

  • 异步的特点:任务不依赖于其他任务的完成。当任务完成时,通过回调、事件通知等方式告知主线程或者其他线程。异步操作通常用于I/O操作或网络请求,避免主线程等待。
  • 例子:一个Web应用的异步请求可以在后台处理数据,而不阻塞UI线程,用户仍然可以继续交互。

互斥(Mutual Exclusion)

互斥是确保在同一时刻,只有一个线程或任务可以访问共享资源。它通过某种机制(如互斥锁、信号量等)来控制对资源的访问,避免多个线程同时访问共享资源,导致数据不一致或冲突。

  • 互斥的特点:只有一个线程能够访问共享资源。其他线程必须等待,直到持有锁的线程释放资源。通过锁、信号量等机制来实现互斥。
  • 例子:在多线程程序中,使用 mutex 来确保多个线程不能同时修改共享变量。

阻塞(Blocking)

阻塞是指当线程或任务在执行过程中遇到某种条件(如等待数据、等待资源等),暂时无法继续执行,进入等待状态。阻塞的任务在条件满足之前不会继续执行,直到资源可用或外部条件发生变化。

  • 阻塞的特点:任务在等待过程中暂停执行,不消耗CPU资源。任务必须等待某些条件或事件的发生。阻塞通常用于资源访问时,等待资源变为可用。
  • 例子:网络请求时,若没有接收到数据,线程会被阻塞,直到数据到达。

非阻塞(Non-blocking)

非阻塞是指任务或操作不会暂停等待条件满足,而是立即返回并继续执行其他任务。非阻塞操作会尽快返回结果,并且不会阻塞其他操作。

  • 非阻塞的特点:任务在执行过程中不会被暂停,甚至在资源不可用时,操作会立即返回。非阻塞操作通常用于提高效率,特别是在I/O操作中。可以通过轮询、回调等方式检查任务状态,而不需要一直等待。
  • 例子:在文件读取操作时,非阻塞I/O允许程序继续执行其他任务,而不是在读取操作完成之前等待。

总结

5.32 父进程与子进程的关系及区别

父进程和子进程的关系在操作系统中是通过进程的创建和管理来体现的。通过系统调用 fork(),父进程创建一个子进程,子进程会继承父进程的大部分资源,但它们在操作系统中是两个独立的进程。

父进程与子进程的关系:

1. 创建关系:

  • 父进程创建子进程:当父进程调用 fork() 函数时,操作系统会创建一个新的进程,这个新进程就是子进程。fork() 函数返回两次——一次在父进程中,返回子进程的 PID;一次在子进程中,返回0。这是父子进程关系的标志。

2. 资源关系:

  • 子进程会继承父进程的大部分属性和资源,如打开的文件、环境变量、当前工作目录等。
  • 子进程是父进程的一个副本,但子进程有自己独立的进程空间。尽管它继承了父进程的数据段、堆、栈等,但每个进程拥有自己的内存空间,父子进程并不共享存储空间(例如堆、栈等),而共享的只有代码段(文本段)。

3. 独立性:

  • 子进程和父进程是相互独立的,它们可以并行执行,子进程可以执行不同的代码路径。子进程在运行时可以创建自己的子进程,形成进程的层次结构。

父进程和子进程的区别:

父进程和子进程之间的通信:

  • 进程间通信(IPC):父进程和子进程可以通过多种方式进行数据交换和通信,包括管道、消息队列、共享内存等。例如,父子进程可以使用 管道(pipe) 来传递数据:

  • 在这个例子中,父进程和子进程通过管道进行通信。子进程向管道写入数据,父进程从管道读取数据并打印。

总结

  1. 父进程是通过 fork() 创建子进程的进程,负责对子进程的管理。
  2. 子进程是由父进程创建的新进程,它会继承父进程的大部分资源,但在内存和进程控制上是独立的。
  3. 父子进程的区别包括进程ID、资源继承、执行代码、进程控制块等。
  4. 父子进程之间可以通过**进程间通信(IPC)**机制进行数据交换和同步。

5.33. 孤儿进程、僵尸进程、守护进程

孤儿进程(Orphan Process)

孤儿进程是指在父进程终止之后,子进程继续运行的情况。当父进程在子进程执行期间提前结束时,子进程变成孤儿进程。孤儿进程会被操作系统的 init 进程(PID为1的进程)接管,成为它的子进程。init 进程负责清理孤儿进程的资源,防止它们成为僵尸进程。

孤儿进程的特点:

  • 父进程终止,子进程仍然继续运行。
  • init 进程接管孤儿进程,确保它能够得到适当的处理。
  • 孤儿进程不会泄漏资源,因为操作系统会将它们的资源回收。

在这个示例中,父进程调用 fork() 创建子进程后,父进程直接退出。子进程会变成孤儿进程,并由 init 进程接管。在执行时,父进程退出后,子进程会继续运行一段时间。

僵尸进程(Zombie Process)

僵尸进程是指已经终止的进程,但它的父进程没有调用 wait()waitpid() 等函数来获取子进程的终止状态。由于父进程未回收它的资源,子进程仍然保留在进程表中,占用进程号,直到父进程清理它。

僵尸进程的特点:

  • 子进程已终止,但父进程未回收其资源。
  • 占用进程表条目,但不再执行任何操作。
  • 父进程需调用 wait() 来收集子进程的终止状态并清理其资源。

  • 这个示例中,父进程创建了子进程,并且父进程没有立刻调用 wait() 来回收子进程。子进程退出后,变成了僵尸进程。直到父进程调用 wait(),子进程的资源才会被回收。
  • 运行过程中,你可以使用 pstop 命令来观察子进程是否变为僵尸进程(显示为 Z 状态)。

守护进程(Daemon Process)

守护进程是一种在后台独立于终端运行的进程。它通常用于执行持续性的任务,例如日志记录、定时任务等。守护进程通常没有控制终端,且不与用户直接交互。它们通常由 init 进程(或其他进程)启动,并在系统启动时就开始运行。

守护进程的特点:

  • 后台运行:守护进程不与终端直接交互,通常在系统启动时就运行。
  • 独立性:守护进程通常不会受到用户或终端的影响,持续运行,直到系统关闭或显式终止。
  • 系统任务:它们负责一些常驻任务,如系统日志、定时任务、服务管理等。

守护进程的实现:

守护进程的实现通常涉及几个步骤:

  1. 创建一个新的会话,脱离控制终端。
  2. 设置 umask(文件权限掩码)为 0。
  3. 将当前工作目录更改为根目录 /,避免守护进程锁定在某个目录下。
  4. 关闭所有文件描述符。

  • 守护进程通常不会与终端交互,因此它的输出不会直接显示在终端。可以通过 pstop 命令查看守护进程在后台运行。守护进程通常会持续运行,不会结束,直到系统关闭或显式终止。

总结

5.34 死锁与活锁

死锁的原因与条件

死锁是指多个进程在执行过程中因争夺资源而互相等待,从而导致所有进程都无法继续执行的状态。

死锁发生的四个必要条件

  1. 互斥条件(Mutual Exclusion):进程对已分配的资源独占,其他进程无法同时访问这些资源。也就是说,某些资源在任何时刻只能被一个进程使用,其他进程需要等待。
  2. 请求保持条件(Hold and Wait):进程已经持有一些资源,但在请求其他资源时未释放已持有的资源。如果其他进程正在占用所需资源,进程会被阻塞,无法继续执行。
  3. 不可剥夺条件(No Preemption):进程已经获得的资源不能被其他进程强行剥夺。即使其他进程需要这些资源,已经持有资源的进程也不能强行剥夺其资源。
  4. 环路等待条件(Circular Wait):存在一个进程链,进程 A 等待进程 B 持有的资源,进程 B 等待进程 C 持有的资源,进程 C 等待进程 A 持有的资源,从而形成一个环路,所有进程互相等待,形成死锁。

死锁与活锁的区别

死锁活锁是多线程编程中可能遇到的两种不同的问题。

死锁(Deadlock)

  • 定义:死锁是指两个或多个线程或进程互相等待对方释放资源,从而导致所有线程或进程都无法继续执行的状态。死锁发生时,进程之间没有任何一个进程能够继续执行,它们都在相互等待对方释放资源。
  • 特征:互相等待:线程无法继续执行,程序停滞。外部干预:需要外部干预来打破死锁,通常通过终止或重启进程来解决。
  • 例子:线程 A 持有资源 X,线程 B 持有资源 Y,线程 A 请求资源 Y,线程 B 请求资源 X,两个线程都无法继续执行,形成死锁。

活锁(Livelock)

  • 定义:活锁是指两个或多个线程虽然不是处于等待状态,但由于不断地互相释放资源而导致线程始终不能执行,资源在多个线程之间不断传递,但没有实际的工作完成。
  • 特征:线程不断释放和获取资源,类似于活跃的死锁,但线程实际上没有停滞。不断调整状态,导致无法完成任务。
  • 例子:线程 A 持有资源 X,线程 B 持有资源 Y。线程 A 释放资源 X,期望获取资源 Y,线程 B 也释放资源 Y,期望获取资源 X。两者之间不断相互“谦让”,但始终无法实际工作。

解决活锁问题的一般策略

  1. 引入随机性:在多线程中,通过引入随机因素,可以打破固定的顺序,从而避免多个线程持续不断地相互“谦让”。比如,在资源请求中引入随机等待时间。
  2. 使用策略:当发生活锁时,可以设计一种策略来解决问题。例如,线程可以放弃一部分工作或转让任务,或者等待一段时间后再重新尝试。
  3. 调整线程优先级:在某些情况下,适当调整线程的优先级可以使某个线程获得更多的执行机会,避免多个线程之间的竞争。
  4. 重新设计算法和协调:如果活锁是由于设计问题导致的,可以重新设计算法或协调机制。例如,避免所有线程都同时尝试抢占资源,而是设计一个合理的请求和处理机制。

总结

5.35 进程调度算法

进程调度算法是操作系统用来决定哪些进程应该获得 CPU 使用权的策略。不同的调度算法有不同的优缺点,适用于不同的场景。以下是常见的几种进程调度算法:

1. 先来先服务(FCFS,First Come First Serve)

  • 描述:按照进程到达的顺序来调度执行,先到达的进程先被执行,直到该进程完成或被阻塞。
  • 优点:实现简单,易于理解。可以确保先到的进程优先执行,避免了进程饥饿的问题。
  • 缺点:非抢占式,即进程一旦开始执行,就无法被中断。如果先到的进程执行时间很长,后到的进程需要等待,可能导致长进程导致短进程的饥饿(即长进程可能会阻塞短进程的执行)。可能导致平均等待时间较长,特别是当进程执行时间差异很大时。

假设有三个进程 P1、P2、P3,它们的到达时间和执行时间如下:

按照 FCFS,进程按照到达时间依次执行。P1 先执行 4 单位时间,执行完成后 P2 执行 3 单位时间,最后 P3 执行 2 单位时间。

执行顺序:

P1 → P2 → P3

进程按照到达时间顺序执行,P1 先执行,之后是 P2 P3。虽然 P2 到达时间为 1,但它需要等待 P1 执行完。

这种算法会导致较长的进程导致短进程等待较久,也就是可能出现较长的等待时间

2. 短作业优先(SJF,Shortest Job First)

  • 描述:根据进程的执行时间来进行调度,执行时间短的进程先被执行。该算法试图减少平均等待时间
  • 优点:在理想情况下,它能最小化平均等待时间(Optimal)。
  • 缺点:需要知道进程的执行时间(或估算)。在实际系统中,这可能是困难的。可能导致长作业饥饿:如果系统中有很多短作业,长作业可能永远无法得到执行。

假设有三个进程 P1、P2、P3,它们的到达时间和执行时间如下:

按照 SJF,进程执行顺序是根据执行时间来决定的,执行时间短的进程优先执行。进程 P1 到达后会先执行,但 P2 到达时执行时间更短,因此在 P1 执行结束后,P2 执行,最后是 P3。

执行顺序:

P3 → P2 → P1

SJF 使得执行时间短的进程优先执行,最小化了平均等待时间。

但也会出现长进程饥饿的问题,P1 必须等 P3 和 P2 执行完才能执行,导致长进程的等待时间过长。

3. 最短剩余时间优先(SRTF,Shortest Remaining Time First)

  • 描述:在执行过程中,根据剩余执行时间来动态调度进程。如果一个新到达的进程的剩余执行时间比当前进程的剩余执行时间短,则进行切换。
  • 优点:可以最小化平均等待时间,与 SJF 相比,SRTF 是动态的,适用于实时系统。
  • 缺点:需要实时计算每个进程的剩余执行时间。可能导致长作业饥饿,因为较短的进程可能不断抢占 CPU。

假设有三个进程 P1、P2、P3,它们的到达时间和执行时间如下:

按照 ,首先 P1 执行,执行时 P

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

作者简介:仅用几个月时间0基础天坑急转嵌入式开发,逆袭成功拿下华为、vivo、小米等15个offer,面试经验100+,收藏20+面经,分享求职历程与心得。 专栏内容:这是一份覆盖嵌入式求职过程中99%问题指南,详细讲解了嵌入式开发的学习路径、项目经验分享、简历优化技巧、面试心得及实习经验,从技术面,HR面,AI面,主管面,谈薪一站式服务,助你突破技术瓶颈、打破信息差,争取更多大厂offer。

全部评论
已老实
1 回复 分享
发布于 2025-03-20 16:32 辽宁

相关推荐

程序员花海:实习和校招简历正确格式应该是教育背景+实习+项目经历+个人评价 其中项目经历注意要体现业务 实习经历里面的业务更是要自圆其说 简历模板尽可能保持干净整洁 不要太花哨的
点赞 评论 收藏
分享
2025-12-15 12:50
河北工程大学
sta666:我也是这个国际商业化的,三天,一天一面,就通过了,不过我是后端实习生,好好面感觉能过。
点赞 评论 收藏
分享
评论
5
6
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务