嵌入式面试笔试与拓展1.4 I/O进程
·
四.I/O进程
-
标准IO和文件IO区别
标准 I/O 和文件 I/O 是编程里用于输入输出操作的两种方式,它们的区别如下:
- 缓冲机制
- 标准 I/O:有缓冲机制,它会先把数据存于缓冲区,等缓冲区满或者满足特定条件时再进行实际的 I/O 操作,这能减少系统调用次数,提高效率。
- 文件 I/O:无缓冲机制,数据直接进行读写操作,每次操作都会引发系统调用。
- 接口类型
- 标准 I/O:提供了更高级的函数接口,像 fopen、fread、fwrite、fclose 等,使用起来较为简便,还支持格式化输入输出。
- 文件 I/O:提供了低级的系统调用接口,如 open、read、write、close 等,对文件操作的控制更精细。
- 可移植性
- 标准 I/O:具有良好的可移植性,在不同操作系统上都能保持一致的行为。
- 文件 I/O:不同操作系统的文件 I/O 接口存在差异,可移植性相对较差。
- 适用场景
- 标准 I/O:适合处理文本文件和格式化数据,能提高开发效率。
- 文件 I/O:适合对性能要求高、需要精细控制文件操作的场景,如底层文件系统操作。
-
简述流指针?
定义
- 流指针类型为 FILE *,指向 FILE 结构体对象,该对象包含文件操作所需信息。
补充
- 在 C 语言里,
FILE(英文:文档,文件的意思)是一种结构体类型,用来表示文件流,涵盖了文件操作所需的各类信息,像文件状态、缓冲区等。FILE *则是指向FILE结构体对象的指针类型。 - 借助这个指针,就能对文件进行打开、读取、写入和关闭等操作。
- 例如
FILE *fp = fopen("test.txt", "r");,这里的fp就是FILE *类型指针,它指向打开的文件对应的FILE结构体对象。
作用
- 标识文件:程序通过流指针识别并操作特定文件。
- 跟踪位置:记录文件读写位置,保证顺序读写。
- 管理缓冲:关联文件缓冲区,提升 I/O 效率。
使用
- 打开:fopen 返回流指针。
- 读写:读写函数以流指针为参数。
- 关闭:fclose 传入流指针。
注意
- 检查:fopen 后检查是否为 NULL。
- 释放:使用完用 fclose 释放资源。
- 有效:文件关闭后流指针失效。
-
简述系统调用?
定义
- 系统调用是用户程序与操作系统内核交互的接口,是操作系统提供给用户程序调用的特殊接口集合。
作用
- 资源管理:帮助用户程序请求操作系统分配和管理 CPU、内存、文件等资源。
- 安全保障:隔离用户程序和内核,防止用户程序直接访问敏感资源,保障系统安全稳定。
- 功能实现:让用户程序借助操作系统实现底层功能,如创建进程、读写文件。
调用过程(类比:下矿洞)
- 陷入内核:用户程序执行特殊指令(如 int 指令)进入内核态。
- 参数传递:通过寄存器或栈传递系统调用号和参数。
- 内核处理:内核根据系统调用号执行相应服务。
- 返回结果:处理完成后返回结果,程序回到用户态。
常见类型
- 进程控制:创建、终止进程等。
- 文件操作:打开、读写、关闭文件等。
- 设备管理:请求、释放设备等。
- 信息维护:获取系统时间等。
-
简述静态库和动态库的区别?
链接时间
- 静态库:在编译时链接,相关代码被完整复制到可执行文件中。
- 动态库:在运行时链接,可执行文件仅存储库的引用信息。
可执行文件大小
- 静态库:使可执行文件体积增大,因为包含了库的全部代码。
- 动态库:可执行文件较小,多个程序可共享一份库代码。
更新维护
- 静态库:库更新时需重新编译整个程序。
- 动态库:只需更新库文件,程序下次运行自动使用新库。
运行性能
- 静态库:无额外的加载开销,运行速度可能稍快。
- 动态库:加载时会有一定性能开销,但多个程序可共享内存,减少内存占用。
依赖关系
- 静态库:可执行文件不依赖外部库文件,可独立运行。
- 动态库:依赖对应的动态库文件,若缺失则无法正常运行。
-
如何将程序执行直接运行与后台?
以下是 Windows :
直接运行
- 方式:双击.exe 文件或在命令行输入程序路径和名称启动。
- 特点:程序在前台运行,占据当前窗口,用户可直接交互,需等待程序执行完毕才能进行其他操作。
后台运行
- 任务计划程序:打开 “任务计划程序” 创建基本任务,设置名称、触发器、操作等,选择要运行的程序。
- 注册为服务:使用 instsrv.exe 和 srvany.exe 工具,将程序注册为 Windows 服务,并通过注册表配置参数。
- 设置应用后台权限:在 “设置”>“应用” 中找到对应应用,在 “高级选项” 中设置 “允许此应用在后台运行”。
以下是Linux :
直接运行
- 操作:在终端输入程序名或脚本名回车,如 ./test.sh。
- 特点:独占终端,运行时无法在该终端操作,直至结束。
后台运行
- 启动时放后台
- 操作:命令后加 &,如 ./test.sh &。
- 特点:启动后后台执行,返回进程 ID,可继续用终端。
- 运行中移后台
- 操作:Ctrl + Z 暂停,再输入 bg。
- 特点:适用于已前台运行的程序。
- 管理后台程序
- 查看:用 jobs 命令。
- 切回前台:fg %n(n 为任务编号)。
- 终止:kill 加进程 ID。
-
进程的状态
三态模型
- 运行态:进程正在 CPU 上执行指令。
- 就绪态:进程已获取除 CPU 外所有必要资源,等待系统分配 CPU 以运行。
- 阻塞态:进程因等待某事件(如 I/O 完成)而暂停执行,放弃 CPU。
五态模型(在三态基础上增加)
- 新建态:进程刚被创建,尚未进入就绪队列。
- 终止态:进程执行完毕或因错误终止,系统正回收资源。
其他特殊状态
- 挂起就绪态:就绪进程被换出内存至外存,待重新调入内存后可参与调度。
- 挂起阻塞态:阻塞进程被换出内存至外存,等待事件发生且被调回内存。
-
什么是僵尸进程?
以下是关于僵尸进程的简洁介绍:
- 定义:子进程终止后,父进程未回收其资源,处于这种状态的子进程就是僵尸进程。
- 产生:子进程结束并向父进程发送结束信号,父进程未用 wait() 或 waitpid() 来获取退出状态与释放资源,致使子进程变为僵尸进程。
- 影响:占用系统的进程资源,如进程控制块,大量出现会耗尽资源,影响新进程创建。
- 识别:用 ps -ef 命令查看,僵尸进程状态显示为 Z或 Z+。
- 处理:父进程正常时,让父进程调用 wait() 或 waitpid() 回收资源;父进程有(病)问题则杀死父进程,让 init 进程接管并回收僵尸进程资源。
-
简述创建子进程中的写时拷贝技术?
定义
写时拷贝(Copy - On - Write,COW)是一种延迟拷贝技术,在创建子进程时不立即复制父进程的内存空间,父子进程共享物理内存页。
工作机制
- 创建子进程:fork () 创建子进程后,父子进程的虚拟地址空间指向相同的物理内存页。
- 只读访问:父子进程对共享内存只读访问时,不复制物理内存页,节省内存和时间。
- 写入操作:当父子进程任一方尝试写入内存时,操作系统为写入方复制一份物理内存页,使写入操作只影响复制后的内存页。
优点
- 高效内存使用:减少内存占用,尤其在创建大量子进程或处理大内存空间时。
- 快速创建进程:避免不必要的内存复制,加快子进程创建速度。
应用场景
- Unix/Linux 系统:广泛用于 fork () 系统调用创建子进程。
- 数据库系统:在创建事务处理子进程时应用,提高性能。
-
多线程较多进程的优势?
资源占用
- 多线程共享进程资源,如内存、文件句柄,切换开销小;多进程有独立地址空间,切换开销大。
通信同步
- 多线程可直接访问共享变量,通信简单;多进程需用 IPC 机制,通信复杂。
创建销毁
- 多线程创建和销毁速度快、开销小;多进程创建和销毁开销大。
并发响应
- 多线程细粒度并发,某线程阻塞不影响整体响应;多进程中一个进程阻塞可能影响整体。
程序设计
- 多线程设计模型贴合思维,适合紧密相关任务并发,结构清晰、易维护。
-
线程池的使用
概念
线程池是管理一组预创建线程的资源池,可避免频繁创建和销毁线程的开销。
使用步骤
- 创建线程池:设定线程数量上限、任务队列大小等参数。
- 提交任务:将任务提交到线程池的任务队列。
- 线程执行:空闲线程从队列取任务执行。
- 任务管理:可对任务排队、等待或拒绝。
- 关闭线程池:不再需要时,有序关闭。
优点
- 提高性能:减少线程创建销毁开销。
- 资源控制:限制线程数量,避免资源耗尽。
- 管理方便:统一管理线程生命周期。
适用场景
- 高并发任务:如 Web 服务器处理请求。
- 任务执行频繁:需快速响应的场景。
-
线程池的组成部分
线程管理器
- 负责线程池的创建、销毁、启动和停止等管理操作。
工作线程
- 线程池中的线程,从任务队列中获取任务并执行。
任务队列
- 存储待执行的任务,工作线程从这里获取任务。
任务接口
- 规定任务的基本形式,提交到线程池的任务需实现该接口。
类比
线程管理器如同公司的管理层,负责组建、解散、启动和暂停公司运营;
工作线程就像员工,从任务清单里领取任务并执行;
任务队列类似任务清单,存放着待完成的工作;
任务接口则是工作的标准规范,所有提交给公司的任务都得按此标准来。
-
线程的同步互斥机制?
同步机制
互斥机制
- 互斥锁:同一时间只允许一个线程访问共享资源,线程访问前加锁,访问完解锁。
- 读写锁:允许多个线程同时读共享资源,但写时独占,提高读操作并发性能。
-
简述互斥锁的实现原理?
- 原子操作:
- 利用硬件指令或特殊 CPU 指令,如测试并设置、比较并交换等,确保锁状态更新的原子性,保证同一时刻只有一个线程能获取锁。
- 线程阻塞与唤醒:
- 获取不到锁的线程被设置为阻塞状态放入等待队列,持有锁的线程释放锁时,操作系统按调度策略从等待队列中唤醒一个线程,使其有机会获取锁。
-
简述死锁的情景?
- 资源竞争死锁:多个线程争夺资源,资源分配顺序不当,如线程 A 持资源 1 等资源 2,线程 B 持资源 2 等资源 1。
- 环路等待死锁:线程间形成资源请求环路,如线程 A 等线程 B,线程 B 等线程 C…… 线程 N 等线程 A。
- 信号量误用死锁:信号量 P、V 操作顺序或次数错误,如线程多次 P 操作但少 V 操作致资源无法正常释放。
-
简述信号量的原理?
- 定义:信号量是一个整数计数器,用于控制对共享资源的访问。
- 操作
- P 操作:信号量值减 1,若结果小于 0,线程阻塞等待。
- V 操作:信号量值加 1,若有等待线程,唤醒一个。
- 原理核心:通过 P、V 操作改变信号量值,控制线程对资源的访问权,实现同步与互斥。
- 类型
- 二值信号量:值为 0 或 1,用于互斥。(租单车)
- 计数信号量:值大于 1,用于控制多个资源的并发访问。(电影院)
-
简述进程的通信机制?
管道
- 匿名管道:父子进程间单向通信,数据先进先出。
- 命名管道:不相关进程也能通信,有路径名。
消息队列
- 消息按类型存储读取,克服管道无格式字节流限制。
共享内存
- 多个进程共享同一块物理内存,速度快但需同步。
信号量
- 用于进程同步与互斥,保证对共享资源的互斥访问。
信号
- 用于通知进程发生了异步事件,如终止信号。
套接字
- 可实现不同主机进程间通信,常用于网络通信。
-
管道的通信原理?
- 基本概念:管道是用于进程间通信的一种机制,本质是内核中的缓冲区。
- 单向传输:数据只能单向流动,一个进程写,另一个进程读。
- 匿名管道:
- 父子进程通过 fork 共享,父进程写端写数据,子进程读端读数据。
- 内核自动管理缓冲区,写满时写进程阻塞,读空时读进程阻塞。
- 命名管道:
- 有路径名,不相关进程可通过路径名访问。
- 读写操作与匿名管道类似,遵循先进先出原则。
-
用户进程对信号的响应方式?
- 默认处理:系统对不同信号有预设处理方式,如终止进程、暂停进程等。
- 忽略信号:进程可选择忽略特定信号,不做任何响应,但像 SIGKILL 和 SIGSTOP 不可忽略。
- 自定义处理:进程通过 signal 或 sigaction 函数指定信号处理函数,收到信号时执行该函数。
-
共享内存通信原理?
- 原理概述:让多个进程访问同一块物理内存区域实现通信。
- 分配内存:操作系统在物理内存开辟共享内存区,为进程建立映射关系。
- 映射关联:各进程将共享内存映射到自己的虚拟地址空间,实现对同区域访问。
- 数据读写:进程直接读写映射的虚拟地址,数据会同步到共享内存。
- 同步控制:因可并发访问,需信号量、互斥锁等同步机制保证数据一致性。
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)