(嵌入式八股)第5章 操作系统(三)
5.21 用户空间与内核通信方式
1. 系统调用(System Call)
系统调用是用户程序通过内核执行特权操作的方式。用户程序通过系统调用向内核请求服务,如读写文件、创建进程等。
代码例程:文件操作系统调用
在用户空间程序中,系统调用如 open
、write
和 close
使得程序能够向内核请求操作文件的服务。通过这些接口,用户程序能访问到硬盘上的文件,而不需要直接操作硬件。
2. 文件接口(File Interface)
文件接口是用户程序通过标准文件操作与内核进行通信的常见方式,允许用户程序通过文件进行数据的读写。
代码例程:文件读写
文件接口通过标准的 C 库函数,如 fopen()
、fgets()
和 fclose()
,允许用户程序与内核中的文件系统进行交互。这是用户程序与内核进行数据交换和管理的一种常见方式。
3. procfs
/proc
是一个虚拟文件系统,用户空间程序通过读取和写入 /proc
文件系统的文件与内核通信,获取或修改内核状态和信息。
代码例程:读取 /proc/cpuinfo
/proc/cpuinfo
提供了关于系统 CPU 的信息。通过读取 /proc
文件系统中的虚拟文件,用户空间程序可以获取系统级的硬件和内核状态信息。
4. sysfs
/sys
是另一个虚拟文件系统,用于提供内核、硬件设备的状态信息。通过读取 /sys
中的文件,用户空间程序可以查询或修改设备属性。
代码例程:读取 /sys/class/net/eth0/address
/sys/class/net/eth0/address
提供了网络接口 eth0
的 MAC 地址。通过访问 /sys
文件系统,用户程序可以查询硬件设备的属性和内核参数。这样可以动态地获取或修改设备信息,常用于设备管理和配置。
5. 共享内存(Shared Memory)
共享内存是一种进程间通信(IPC)机制,允许多个进程共享一块内存区域。这是最快的进程间通信方式,因为进程之间无需复制数据。
代码例程:创建和使用共享内存
6. 设备文件(Device Files)
设备文件是用户空间程序与内核之间进行通信的常见方式,设备文件代表了硬件设备,如串口、硬盘、字符设备等。
代码例程:通过设备文件访问串口设备
/dev/ttyS0
)。通过设备文件,用户空间程序可以与内核中的硬件设备进行通信。该例子展示了如何通过打开、写入和关闭设备文件来与串口设备进行交互。
5.22 进程、线程及之间区别
1. 进程(Process)
- 定义:进程是操作系统资源分配的基本单位,表示一个正在运行的程序。每个进程都有自己的地址空间、数据、程序计数器和系统资源。
- 资源:每个进程拥有独立的地址空间和系统资源(如内存、文件描述符等)。进程之间相互独立,不共享资源。
- 功能:进程是程序的实体,负责管理程序的运行,包含代码、数据以及程序的执行状态。
- 创建与销毁:进程的创建和销毁需要较大的开销,因为操作系统需要分配和回收大量的资源。
- 通信:进程之间不能直接共享数据,通常需要通过进程间通信(IPC)机制,如管道、消息队列、共享内存等进行数据交换。
2. 线程(Thread)
- 定义:线程是进程中的实际执行单位,是操作系统调度的最小单位。一个进程可以有多个线程,这些线程共享进程的地址空间和资源。
- 资源:线程共享同一进程的地址空间和资源(如内存、文件描述符),但每个线程有自己的栈空间、程序计数器和局部变量。
- 功能:线程负责在进程中执行具体的任务。线程之间的协作比进程之间的协作更加高效。
- 创建与销毁:线程的创建和销毁比进程轻便,开销较小,因为线程之间共享资源,操作系统只需要为每个线程分配最小的资源。
- 通信:线程之间通信更加方便,因为它们共享同一进程的内存,可以直接访问共享内存或通过互斥锁等机制同步数据。
进程与线程的主要区别
进一步分析:
1. 内存和资源:
- 进程:每个进程都有自己的内存空间和资源,这意味着一个进程崩溃时不会直接影响到其他进程。但是,进程之间的通信需要通过特定的机制(如消息队列、管道、共享内存等)。
- 线程:线程共享同一个进程的内存和资源,这使得线程间的通信更加高效,但也带来了同步问题(如数据竞争、死锁等)。如果一个线程崩溃,可能导致整个进程崩溃。
2. 性能:
- 进程:由于每个进程都有自己的地址空间和资源,进程间的切换开销较大。创建和销毁进程需要更多的系统资源。
- 线程:线程之间共享资源,创建和销毁线程的开销较小。线程间切换比进程切换更快,因此在需要频繁调度的情况下,使用线程可以提高性能。
3. 安全性和稳定性:
- 进程:进程相互独立,避免了一个进程的崩溃影响其他进程。操作系统可以为每个进程分配不同的资源和优先级。
- 线程:线程共享进程的内存,因此它们之间的错误(如访问未初始化的内存)可能导致整个进程崩溃。因此,线程的管理和同步需要特别注意。
总结:
- 进程是资源分配的基本单位,它有独立的地址空间和资源。每个进程相互独立,进程间通信相对较慢,但更加稳定。
- 线程是执行单位,多个线程共享进程的资源,线程间通信更加高效。线程的创建和销毁较为轻量,但一个线程的崩溃可能影响整个进程的稳定性。
5.23 进程的状态
操作系统中的进程可以处于多种不同的状态,这些状态反映了进程在不同阶段的活动或等待。进程状态管理是操作系统中至关重要的部分,因为它决定了进程如何被调度和执行。以下是六种主要的进程状态:
1. 就绪态(Ready)
- 定义:就绪态是指进程已经准备好执行,只等待 CPU 调度。该进程已经分配了必要的资源,并且可以立即运行,只要操作系统为其分配 CPU 时间。
- 特征:进程进入就绪态后,操作系统会将其放入就绪队列中,等待 CPU 分配时间。此时,进程已经准备好执行,但还没有被调度执行。
- 典型操作:当一个进程的时间片用完后,它会从运行态转为就绪态,等待下次 CPU 调度。
2. 运行态(Running)
- 定义:运行态是指进程正在 CPU 上执行。进程从就绪态进入运行态后,会被操作系统调度到 CPU 上,并开始执行程序的指令。
- 特征:在运行态下,进程会执行其代码,并使用 CPU 来进行计算和处理任务。运行中的进程是唯一可以执行的进程,除非它被抢占或执行完成。
- 典型操作:一旦调度程序选择一个就绪态的进程并分配 CPU 时间片,进程就会进入运行态。
3. 僵尸态(Zombie)
- 定义:僵尸态进程是已经终止(退出)的进程,但是其父进程尚未调用
wait()
或waitpid()
来回收该进程的资源。此时,虽然进程已经完成执行,但它仍然保留在系统中,等待父进程清理。 - 特征:在僵尸态下,进程的资源(如内存)已经释放,但进程的进程控制块(PCB)还没有被完全销毁。进程仅占用进程表中的一个条目,等待父进程清理。
- 典型操作:一旦父进程调用
wait()
等待已终止子进程,僵尸进程将被完全清除。
4. 可中断睡眠状态(浅度睡眠,Interruptible Sleep)
- 定义:可中断睡眠状态表示进程正在等待某些事件或资源,但它仍然能够接收中断信号。如果有外部事件或信号发生,进程可以被唤醒并转为就绪态。
- 特征:处于可中断睡眠的进程通常等待某些条件(如 I/O 操作完成)。如果收到信号(如 SIGINT),进程会被唤醒并进入就绪态。
- 典型操作:一个进程发起 I/O 操作或等待某个条件时进入该状态,通常可以通过外部信号唤醒。
5. 不可中断睡眠状态(不可中断等待,Uninterruptible Sleep)
- 定义:不可中断睡眠状态表示进程正在等待某些资源(如 I/O 操作),并且在等待过程中不能被中断。进程必须等待所需资源或事件的完成,不能响应信号(如中断或终止信号)。
- 特征:进程在此状态下无法被信号中断,通常用于对外部硬件或资源的等待,直到相应的资源准备好。此状态称为深度睡眠。
- 典型操作:例如,进程等待硬盘 I/O 完成时,通常处于不可中断睡眠状态。
6. 暂停态(Stopped)
- 定义:暂停态表示进程被暂停,通常是由于接收到特定的信号(如 SIGSTOP 或 SIGTSTP)。在暂停态下,进程暂停执行,但它并没有完全结束,仍然存在于系统中,等待恢复。
- 特征:进程处于暂停态时,它不再消耗 CPU 时间,但可以被操作系统恢复。恢复后,进程会转为就绪态,等待下次调度执行。
- 典型操作:通过发送 SIGSTOP 信号暂停进程,通过 SIGCONT 信号恢复进程执行。
总结:
状态转换的过程:
- 从就绪态到运行态:当 CPU 调度器选择一个进程并分配 CPU 时间片时,进程从就绪态转入运行态。
- 从运行态到睡眠态:如果进程在运行过程中需要等待某些资源(如 I/O 完成),它会进入睡眠态。如果是可中断睡眠,可以被信号唤醒;如果是不可中断睡眠,需要等待外部条件。
- 从睡眠态到就绪态:当等待的条件满足时,进程会从睡眠态转回就绪态,等待 CPU 调度。
- 从运行态到僵尸态:进程执行完毕,但其父进程尚未回收其资源,进程变为僵尸态。
- 从暂停态到就绪态:当进程收到恢复信号(如 SIGCONT)时,它会从暂停态恢复,进入就绪态。
5.24 进程/线程选用的时机
在操作系统设计中,选择进程还是线程取决于应用程序的需求,特别是在资源管理、任务隔离、并发性和实时性等方面。进程和线程都有其独特的优势和使用场景。以下是使用进程和使用线程的具体情况分析。
使用进程的情况:
1. 需要独立的地址空间和系统资源
- 应用场景:当任务之间需要完全独立的环境,且需要较强的数据隔离时,应选择使用进程。每个进程有自己的内存空间和资源,不会直接影响其他进程。
- 例子:运行多个独立的应用程序或服务,如浏览器和数据库服务器,它们需要独立的内存和文件资源。
2. 需要更高的安全性和稳定性
- 应用场景:如果一个任务的崩溃不应该影响其他任务的正常运行,使用进程可以提高系统的稳定性。进程是独立的,进程崩溃时不会直接影响其他进程。
- 例子:在操作系统中,系统进程和用户进程应该分开,避免系统崩溃导致所有用户程序的崩溃。浏览器和操作系统的核心进程应该隔离,防止恶意网页或程序影响操作系统的稳定性。
3. 并行计算需求
- 应用场景:在多核处理器的情况下,进程可以充分利用多核的计算能力进行并行计算。每个进程可以在不同的 CPU 核心上独立执行,达到更高的计算效率。
- 例子:大规模的科学计算或数据处理任务,例如分布式数据库和视频编码任务。
使用线程的情况:
1. 共享数据和资源
- 应用场景:如果多个任务需要频繁共享数据和资源,并且需要较高效的通信,使用线程是更好的选择。线程之间可以直接访问同一个进程的地址空间,因此共享数据和资源变得更方便。
- 例子:在 Web 服务器中处理多个请求,多个线程可以共享数据库连接池,减少资源的占用和数据传输的开销。
2. 轻量级任务
- 应用场景:当任务较轻且需要频繁切换时,线程比进程更加轻量级。线程切换的开销远小于进程切换,因此当任务相对简单且需要快速调度时,线程更合适。
- 例子:一个图形界面程序中的按钮点击事件处理,每个事件可以通过一个线程来处理,线程切换快速且开销小。
3. 实时性要求
- 应用场景:如果任务对实时性有较高的要求,线程能够快速响应并处理任务。线程在同一进程内共享资源,因此线程之间的调度和通信速度较快,适合实时任务的处理。
- 例子:音视频处理、游戏开发等需要快速响应用户输入和数据处理的场景。多个线程可以在后台处理实时数据流,同时保持界面的响应性。
进程与线程的对比总结:
总结:
- 使用进程:当需要隔离任务、提高系统稳定性或进行计算密集型任务时,使用进程。进程是操作系统中资源分配的基本单位。
- 使用线程:当任务之间需要共享数据、高效通信并且任务轻量时,使用线程。线程之间的创建和销毁较为轻便,适合处理实时任务和频繁切换的任务。
5.25 多进程的优缺点
多进程的优点:
1. 独立性
- 每个进程有独立的内存空间和资源。当一个进程发生崩溃时,它不会影响到其他进程的执行。因此,进程之间相互独立,可以有效地避免一个进程的错误影响整个系统的稳定性。
- 例子:如果浏览器进程崩溃,它只会影响当前打开的标签页,而其他标签页的浏览器进程不受影响。
2. 安全性
- 进程之间的内存是隔离的,进程无法直接访问或修改其他进程的内存空间。这种内存隔离为进程之间提供了较高的安全性,尤其是在处理敏感数据时。
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
作者简介:仅用大半年时间0基础天坑急转嵌入式开发,逆袭成功拿下华为、vivo、小米等15个offer,面试经验60+,收藏20+面经,分享自己的求职历程与学习心得。 专栏内容:最新求职与学习经验,详细讲解了嵌入式开发的学习路径、项目经验分享、简历优化技巧、面试心得及实习经验,从测评,笔试,技术面,HR面,AI面,主管面,谈薪一站式服务,助你突破技术瓶颈、打破信息差,争取更多大厂offer。