嵌入式 Linux 学习 | 进程编程开发(Day05)超详细复习笔记(Linux 文件 IO 复盘|glob/getopt|fork 进程创建|exec 进程替换|shell 模拟实战作业)

📅 2026/7/3 14:25:30
嵌入式 Linux 学习 | 进程编程开发(Day05)超详细复习笔记(Linux 文件 IO 复盘|glob/getopt|fork 进程创建|exec 进程替换|shell 模拟实战作业)
前言本篇为嵌入式 Linux 系统编程第五天完整复盘笔记开篇先整理当日早测全套 Linux 文件 IO、用户信息、目录解析、时间转换等口述考点再讲解glob文件匹配、getopt命令行参数解析两大工具函数核心重点讲解 Linux 进程完整体系进程定义、资源分配、fork 创建子进程、进程继承属性、8 种进程终止方式、atexit/on_exit终止回调、wait回收子进程、exec 族进程替换函数最后配套质数筛选多进程优化、简易 shell 模拟两大课堂作业。一、当日早测全套口述考点Linux 文件 IO 系统基础早测全部为简答题覆盖前几日文件 IO、标准 IO、目录、时间、用户信息核心知识点完整标准答案整理如下1. 文件的元信息都有什么文件元信息是不包含文件真实内容、用于描述文件属性的配套信息通过stat/lstat/fstat函数读取核心包含文件类型普通文件、目录、管道、软链接、设备文件等文件权限rwx 读写执行权限、SUID/SGID 特殊权限位文件归属UID 文件所有者、GID 所属用户组文件大小字节为单位的文件体积时间戳最后访问时间 atime、最后修改内容 mtime、最后修改属性 ctime文件硬链接计数、文件存储设备号、inode 编号、文件读写块大小等。2. Linux 文件类型有几种分别是Linux 共 7 种基础文件类型通过 stat 结构体st_mode判断-普通文件文本、二进制、可执行程序d目录文件存放文件索引与 inode 映射l软链接文件符号链接指向其他文件路径b块设备文件硬盘、SD 卡等块存储设备c字符设备文件串口、键盘、LED 等字节流外设p管道文件匿名管道进程间单向通信s套接字文件本地 socket进程间双向通信。3. 文件 IO 中文件描述符是什么文件 IO 属于系统调用open/read/write/close文件描述符 fd 是内核分配给进程的非负整型索引进程打开文件时内核在进程文件描述符表分配一个数字0 标准输入、1 标准输出、2 标准错误默认自动打开所有读写操作均通过 fd 告知内核操作哪个文件进程独立 fd 表不同进程相同 fd 代表不同文件。4. 标准 IO 中文件流是什么标准 IOfopen/fread/fprintf封装在 C 库层核心载体为FILE*文件流指针对底层文件描述符做上层封装内置缓冲区统一屏蔽不同系统底层 IO 差异跨平台兼容性更好一个 FILE 流绑定一个底层 fd操作时库函数自动管理缓存。5. 标准 io 缓存有哪些类型有什么作用如何刷新缓存三种缓存类型全缓冲缓冲区填满才触发真实系统调用写磁盘普通文件默认行缓冲读到换行符\n自动刷新标准输出 stdout 默认无缓冲无缓存每次调用直接下发系统调用标准错误 stderr 默认。缓存核心作用减少系统调用次数降低 CPU 内核态 / 用户态切换开销大幅提升读写性能。缓存刷新方式主动刷新fflush(FILE* stream)强制刷新指定流fflush(NULL)刷新所有打开流被动刷新缓冲区写满、行缓冲读到换行、程序正常 exit 退出、文件 fclose 关闭强制不刷新_exit()/_Exit()直接调用内核跳过库缓存刷新。6. 如何解析目录两种主流方案系统调用目录 APIopendir()打开目录→readdir()循环读取目录项→closedir()关闭读取每一个文件 inode、文件名、文件类型glob 函数通配符批量匹配目录文件自动遍历匹配*?等通配路径。7. 如果想读文件的一行你有哪些方式标准 IOfgets(buf, size, fp)按行读取读到换行停止标准 IOgetline(buf, len, fp)动态分配缓冲区自动适配长行文件 IO 底层read()循环读取字节手动判断\n分割行自行封装行读取逻辑。8. 如何将时间戳转换为格式化的时间字符串完整调用链路time_t t time(NULL)获取秒级时间戳struct tm* tm localtime(t)时间戳转本地时间结构体strftime(buf, sizeof(buf), %Y-%m-%d %H:%M:%S, tm)自定义格式化输出时间字符串。9. Linux 中用户的信息存储在哪个文件密码存储在哪个文件分别用哪些函数解析用户基础信息/etc/passwd解析函数getpwuid()、getpwnam()用户加密密码/etc/shadow仅 root 可读解析函数getspuid()、getspnam()。二、今日新课核心知识点2.1 glob 文件通配符匹配函数核心作用模拟 shell 命令行通配符解析自动匹配带*、?的路径批量获取目录下匹配文件列表。 示例命令行/etc/*代表匹配 /etc 目录下所有文件代码中使用glob()可实现相同效果无需手动遍历目录拼接字符串。 函数原型int glob(const char *pattern, int flags, int (*errfunc)(const char *epath, int eerrno), glob_t *pglob);匹配结果存放在glob_t结构体遍历gl_pathv数组获取所有匹配文件名。2.2 getopt (3) 命令行参数解析用于解析程序启动时传入的短选项如./a.out -l -p 8080自动拆分选项、选项参数替代手动循环切割 argv 字符串简化命令行工具开发。2.3 Linux 进程完整体系2.3.1 对应教材章节进程基础7、8、9、13 章进程信号 / 替换10、15 章。2.3.2 进程核心概念官方定义进程是操作系统分配系统资源的最小单位是正在内存中执行的程序实例程序是磁盘静态二进制文件进程是运行时动态实体。进程独占资源划分以单个进程为隔离单位进程表项操作系统为每一个进程单独分配一条进程控制块 PCB存储进程所有核心属性独立虚拟内存空间每个进程拥有一套独立虚拟地址映射表fork 创建子进程时采用写时复制 COW 机制默认不共享物理内存独立终端会话、独立 UID/GID 权限标识、独立文件描述符表Shell 与进程关系shell 本质是运行在终端的前台进程输入命令后 shell 创建子进程执行对应程序。2.3.3 进程完整生命周期创建 → 调度运行 → 终止创建fork 生成子进程调度操作系统内核调度器分时分配 CPU 时间片切换进程运行终止进程执行完毕或异常崩溃释放资源父进程调用 wait 回收残留 PCB。查看系统全部运行进程命令ps axj可查看 PID、PPID 父进程 ID、终端、CPU 占用、命令等信息。2.4 进程创建 fork (2)1. 函数原型pid_t fork(void);2. pid_t 进程标识类型本质为非负整型数据最小值 0调用getpid()获取当前进程自身 PIDgetppid()获取父进程 PID。3. fork 返回值三重逻辑返回负数fork 创建失败资源不足返回 0当前代码运行在子进程返回正数子进程 PID当前代码运行在父进程。4. 子进程从父进程继承的全部属性fork 瞬间子进程复制父进程几乎所有上下文无需重新初始化所有已打开的文件描述符当前绑定的终端会话用户 UID、用户组 GID文件权限屏蔽字 umask信号处理函数、当前工作目录、环境变量、缓存区数据 不继承PID、PPID、CPU 运行时间、异步 IO 上下文。2.5 进程终止共 8 种终止方式分为正常 / 异常两大类第一类5 种正常终止主动退出可传递退出状态码main 函数执行 return 返回程序任意位置调用标准库exit(3)调用系统调用_exit(2)/_Exit(2)进程最后一个执行线程从线程入口函数 return 返回进程最后一个线程调用pthread_exit(3)线程退出函数。第二类3 种异常终止程序被动崩溃无正常退出码收到内核致命信号强制终止段错误、数组越界、重复释放内存、总线错误等代码主动调用abort(3)触发 SIGABRT 信号自杀进程最后一个线程响应线程取消请求被动终止。2.5.1 C 程序启动与终止底层流程参考教材 167 页流程图内核加载程序后先执行系统启动例程_start_start初始化标准 IO、环境变量调用用户 main 函数main 执行完毕后自动调用exit(status)exit 会逆序执行所有注册的终止回调函数刷新标准 IO 缓存最终调用_exit进入内核销毁进程。2.5.2 终止处理函数注册 atexit /on_exit作用用户提前注册回调函数进程调用exit()正常退出前自动执行执行规则逆序执行后注册的函数优先调用区别atexit(void (*func)(void))无参数回调on_exit(void (*func)(int status, void *arg), void *arg)可传递退出状态与自定义参数关键区分_exit(0)直接调用内核系统调用不会刷新标准 IO 缓存、不会执行 atexit 注册的终止函数直接销毁进程。2.5.3 课堂练习多进程质数筛选优化需求判断一个数字是否为质数单进程耗时 1s范围 100~300 共 201 个数字要求整体耗时控制在 1s 内。基础思路一个数字创建一个子进程201 个进程并行计算全部同时运行总耗时 1s资源优化方案频繁创建大量进程消耗内存、PID 资源限制固定 4 个子进程父进程维护任务列表循环给空闲子进程分配数字任务进程复用降低系统开销。2.6 等待子进程终止 wait (2)核心功能回收已结束子进程 PCB 资源俗称收尸子进程终止后不会立刻释放资源会变为僵尸进程父进程调用wait(int *wstatus)阻塞等待任意一个子进程退出读取退出状态释放子进程内核资源避免僵尸进程堆积。2.7 进程替换 exec 函数族2.7.1 使用场景网络服务程序父进程 fork 子进程子进程 exec 替换为业务处理程序Shell 命令行shell fork 子进程后调用 exec 加载外部命令程序ls/cat/mkdir 等。2.7.2 函数共性exec 族为可变参数函数参数列表末尾以NULL作为结束标记执行成功后直接替换当前进程代码段原有代码不再执行仅执行失败时返回 - 1。2.7.3 五大 exec 函数详细区分函数名参数特征路径查找规则使用示例execlllist 可变参数列表必须传入完整程序绝对路径execl(/bin/ls, ls, -l, /home, NULL);execvvvector 参数存 char * 数组完整绝对路径char *argv[]{ls,-l,/home,NULL}; execv(/bin/ls,argv);execlpl 可变参数 p 自动搜 PATH仅传程序名自动遍历 PATH 环境变量查找execlp(ls,ls,-l,NULL);execvpv 数组参数 p 自动搜 PATH仅传程序名自动匹配 PATHchar *argv[]{ls,-l,NULL}; execvp(ls,argv);补充字符串分割工具解析命令行字符串时拆分参数推荐strsep()线程安全、strtok()切割空格分隔的命令参数。2.8 课堂作业 1模拟简易 Shell 命令行完整实现逻辑框架#include stdio.h #include stdlib.h #include unistd.h #include string.h #include sys/wait.h int main(void) { char buf[128]; char *argv[32]; char *p; while(1) { // 1.打印命令提示符 printf(my_shell ); fflush(stdout); // 2.读取整行输入命令 getline(buf, (size_t){128}, stdin); // 去除末尾换行符 buf[strcspn(buf, \n)] \0; // 3.strsep切割字符串拆分命令参数存入argv数组 int argc 0; p strsep(buf, ); while(p ! NULL) { argv[argc] p; p strsep(buf, ); } argv[argc] NULL; // 空命令跳过 if(argc 0) continue; // 4.fork创建子进程执行命令 pid_t pid fork(); if(pid 0) { // 子进程execvp替换进程执行外部命令 execvp(argv[0], argv); // exec失败才会执行到这里 perror(execvp failed); _exit(-1); } else if(pid 0) { // 父进程阻塞等待子进程执行完毕 wait(NULL); } } return 0; }执行逻辑说明循环读取用户输入→分割参数→创建子进程→子进程调用 execvp 执行系统命令→父进程 wait 回收子进程复刻真实 shell 基础执行逻辑。2.9 课堂作业 2进程注册多个终止回调函数需求为进程注册 3 个 atexit 终止处理函数打印区分先后顺序验证后注册先执行规则示例代码#include stdio.h #include stdlib.h void func1(void) { printf(回调函数1执行\n); } void func2(void) { printf(回调函数2执行\n); } void func3(void) { printf(回调函数3执行\n); } int main(void) { // 注册顺序1→2→3 atexit(func1); atexit(func2); atexit(func3); printf(主程序运行结束准备exit\n); exit(0); }预期输出顺序主程序运行结束准备exit 回调函数3执行 回调函数2执行 回调函数1执行完美验证逆序执行规则。三、本章核心知识点总结早测 Linux 文件 IO 体系文件元信息、7 类文件、fd/FILE 流、三类缓存、目录解析、行读取、时间戳转换、用户信息文件与解析函数工具函数glob 实现通配文件匹配getopt 解析命令行短参数进程基础进程是资源分配最小单位fork 复制进程、写时复制虚拟内存、继承父进程绝大多数属性进程终止8 种终止方式exit 执行注册回调并刷新缓存_exit 直接内核退出无回调atexit 逆序执行终止函数多进程优化大量计算任务可并行 fork 提速进程过多时采用固定进程池分配任务节约资源wait 回收子进程防止僵尸进程exec 进程替换区分 execl/execv/execlp/execvp 路径与参数传递差异搭配 fork 实现 shell、服务器多任务架构实战作业简易 shell 模拟、多回调终止函数验证、多进程质数并行计算。补充拓展易错点fork 后父子进程共享文件偏移量同时读写同一文件会互相覆盖exec 执行成功后不会返回仅失败才会向下执行错误处理代码子进程终止后父进程不调用 wait 会产生僵尸进程长期运行占用系统 PID 资源stdout行缓冲fork 前不 fflush 会导致父子进程重复打印缓存内容execp 自动读取 PATH 环境变量无需填写程序绝对路径开发命令行工具更便捷。