当前位置: 首页 > news >正文

《密码系统设计》第十周预习

20231313 张景云《密码系统设计》第十周预习


AI对内容的总结Headfirst C

进程间通信(IPC)核心知识总结

一、核心基础:文件描述符与数据流

  1. 进程通过文件描述符(非负整数)管理数据流,描述符表固定前3项:0(标准输入,键盘)、1(标准输出,屏幕)、2(标准错误,屏幕),其余项动态分配给文件、网络连接等数据流。
  2. 数据流不仅限于文件,还包括键盘、屏幕、管道、网络连接等,文件描述符是进程操作数据流的唯一标识。

二、输入输出重定向

  1. 核心原理:修改描述符表中对应编号的数据流指向,即可改变输入/输出的目标(如从屏幕转向文件)。
  2. 关键函数:
    • fileno(FILE *fp):根据文件指针获取对应的文件描述符编号。
    • dup2(int oldfd, int newfd):将oldfd对应的数据流复制到newfd,实现重定向(如dup2(fileno(f), 1)将标准输出重定向到文件f)。
  3. 命令行重定向:>重定向标准输出(等价于1>),2>重定向标准错误,2>&1将标准错误合并到标准输出。

三、进程等待与同步

  1. 问题场景:子进程未完成任务时父进程可能提前退出,导致数据丢失(如文件未写入完成)。
  2. 解决方案:waitpid(pid_t pid, int *status, int options)函数,父进程阻塞等待指定子进程结束。
  3. 状态获取:通过WEXITSTATUS(status)宏提取子进程退出状态(pid_status的前8位存储退出状态,其余位存储其他信息)。

四、管道通信(实时进程交互)

  1. 管道特性:单向通信,连接两个进程的数据流,数据从写入端传入、读取端读出,无需中间文件存储。
  2. 关键函数:pipe(int fd[2])创建管道,fd[0]为读取端,fd[1]为写入端。
  3. 父子进程管道通信流程:
    • 父进程创建管道,调用fork()生成子进程(子进程继承管道描述符)。
    • 子进程:关闭读取端(fd[0]),用dup2(fd[1], 1)将标准输出重定向到管道写入端。
    • 父进程:关闭写入端(fd[1]),用dup2(fd[0], 0)将标准输入重定向到管道读取端。
    • 子进程的输出通过管道实时传递给父进程,实现高效通信。
  4. 有名管道(FIFO):通过mkfifo()创建,允许非父子进程通过管道名通信。

五、信号机制(进程控制与异常处理)

  1. 信号本质:操作系统向进程发送的短消息(整型值),用于通知进程事件(如中断、错误、超时等)。
  2. 核心信号类型及含义:
    • SIGINT:进程被中断(如Ctrl+C);
    • SIGTERM:请求终止进程(默认kill命令);
    • SIGALRM:闹钟超时信号(由alarm()触发);
    • SIGPIPE:向无读取端的管道写入数据;
    • SIGKILL:强制终止进程(无法捕捉或忽略)。
  3. 信号处理:
    • 自定义处理器:通过sigaction()函数注册信号处理函数,替换默认行为(如进程退出前关闭资源)。
    • 关键函数:catch_signal(int sig, void (*handler)(int))简化信号注册流程;raise(int sig)让进程向自身发送信号。
    • 定时器:alarm(int seconds)设置间隔定时器,到期触发SIGALRM信号,不可与sleep()同时使用。

六、核心要点与注意事项

  1. 进程间通信方式:重定向(文件中转)、管道(实时交互)、信号(事件通知),按需选择。
  2. 资源管理:打开的文件描述符、管道需及时关闭,避免资源泄漏。
  3. 信号安全:信号处理器代码应短而高效,避免使用可能引发冲突的I/O操作。
  4. 兼容性:不同操作系统(Windows/Linux/Mac)的命令与接口存在差异(如打开URL的命令),需适配处理。

对 AI 总结的反思


一、核心基础:文件描述符与数据流

你准确指出了文件描述符的本质及其在进程通信中的核心地位。
补充说明

  • 文件描述符表是每个进程独立的,但子进程会继承父进程的描述符表(通过fork())。
  • 除了0、1、2之外,新打开的文件或管道会占用最小的可用描述符编号(通常是3、4、5…)。

二、输入输出重定向

你清晰地解释了重定向的原理和关键函数。
补充说明

  • dup2() 不仅复制数据流,还会自动关闭 newfd 原先指向的数据流(如果已打开)。
  • 命令行中 2>&1 的含义是“将标准错误重定向到标准输出当前指向的地方”,注意顺序很重要。

三、进程等待与同步

你正确指出了 waitpid() 的作用和状态提取方式。
补充说明

  • waitpid() 的 options 参数常用值:
    • 0:阻塞等待;
    • WNOHANG:非阻塞,立即返回;
  • 除了 WEXITSTATUS(),还有:
    • WIFEXITED(status):判断是否正常退出;
    • WIFSIGNALED(status):判断是否被信号终止。

四、管道通信

你准确描述了无名管道和有名管道的使用场景和区别。
补充说明

  • 管道是字节流,没有消息边界,读写端需要自行约定格式(如换行符分隔)。
  • 如果读端关闭后写端继续写入,会触发 SIGPIPE 信号(默认终止进程)。
  • 双向通信需创建两个管道,一个用于父→子,一个用于子→父。

五、信号机制

  • 你全面覆盖了信号的类型、处理方式和定时器使用。
    补充说明
  • SIGKILLSIGSTOP不可捕获、不可忽略、不可阻塞的信号,用于强制控制进程。
  • alarm() 是“单次定时器”,重复调用会重置定时器。
  • 信号处理函数中应避免调用非异步信号安全函数(如 printf, malloc),可能导致未定义行为。

六、核心要点与注意事项

你总结了通信方式、资源管理和兼容性问题,非常实用。
补充说明

  • 在多线程程序中使用信号要格外小心,信号可能被任意线程处理。
  • 在类Unix系统中,可以使用 fcntl() 设置文件描述符的非阻塞模式,适用于管道和网络通信。

mermaid 代码与截图

  root((进程间通信))文件描述符核心概念非负整数标识进程独立表子进程继承固定描述符0: stdin1: stdout  2: stderr动态分配最小可用编号多种数据流输入输出重定向核心原理修改描述符指向关键函数filenodup2命令行操作输出重定向错误重定向错误合并进程等待与同步问题场景时序不一致数据丢失解决方案waitpid阻塞等待非阻塞等待状态分析WEXITSTATUSWIFEXITED管道通信无名管道单向通信pipe创建父子进程有名管道mkfifo任意进程注意事项信号处理资源关闭信号机制信号类型SIGINTSIGTERMSIGALRMSIGKILL信号处理sigactionraise定时器alarm单次定时核心要点通信方式重定向管道信号资源管理及时关闭避免泄漏

deepseek_mermaid_20251108_dd7a00

基于AI的学习

image

学习实践过程遇到的问题与解决方式(AI 驱动)


问题一:管道通信中的数据读取阻塞与进程僵局

1. 问题描述:
在编写父子进程通过管道通信的代码时,父进程创建管道后fork()出子进程。设计目标是父进程向子进程发送一个命令,子进程执行后返回结果。但程序经常执行到一半就“卡住”不动了,无法正常结束。

2. 解决过程:

  • 初步分析:我首先怀疑是管道读写逻辑错误。检查了pipe()fork()read()write()的调用顺序,看起来符合教程示例。
  • AI诊断:我将代码片段和现象描述给AI。AI立刻指出了几个关键点:
    • 管道缓冲区大小有限:如果写入数据量超过缓冲区大小(通常64KB),写操作会阻塞,直到有数据被读取。
    • 读写端未正确关闭:在我的代码中,父子进程都没有及时关闭不使用的管道端。例如,子进程在读取父进程的数据后,其写入端没有关闭。当父进程试图读取子进程的返回结果时,因为子进程的写入端还开着,父进程的read()会一直等待更多数据,即使子进程已经写完所有数据并退出。
    • 形成了死锁:父进程在等子进程关闭管道(表示数据结束),子进程已经退出但操作系统还为其保留着打开的管道端,导致双方都在等待。

3. 解决方案:
遵循AI的建议,严格执行“谁不用,谁就关”的原则:

int fd[2];
pipe(fd);pid_t pid = fork();
if (pid == 0) {// 子进程:关闭不使用的写入端close(fd[1]);// ... 读取数据、处理、返回结果 ...close(fd[0]); // 返回结果后,读取端也关闭exit(0);
} else {// 父进程:关闭不使用的读取端close(fd[0]);// ... 写入数据 ...close(fd[1]); // 写完数据后,写入端关闭,子进程读端会收到EOF// ... 等待子进程 ...
}

通过精确管理文件描述符的生命周期,程序成功避免了阻塞,能够稳定运行并正常退出。


问题二:信号处理器中执行了不安全的操作

1. 问题描述:
为了优雅地处理程序中断(如Ctrl+C),我编写了一个信号处理器,在收到SIGINT信号时打印一条告别信息并清理资源。然而,程序在特定情况下按下Ctrl+C后,会偶尔发生崩溃或输出乱码,而不是显示预期的信息。

2. 解决过程:

  • 初步分析:起初认为是一般的内存访问错误或逻辑缺陷,但常规调试(如printf)在信号场景下难以进行。
  • AI诊断:向AI描述了信号处理器内的代码和随机崩溃的现象。AI明确指出这是典型的“信号安全”问题:
    • 异步信号不安全函数:我在信号处理器中使用了printf()printf()及其相关的标准I/O函数内部使用了全局数据结构,并且不是可重入的。当主程序正在执行printf()时被信号中断,信号处理器又调用printf(),可能导致内部状态被破坏,引发崩溃或乱码。
    • 受限的执行环境:信号处理器是在一个不确定的、异步的上下文中被调用,它可能中断任何正在执行的指令。因此,在其中只能调用明确被标记为“异步信号安全”的函数。

3. 解决方案:
AI建议使用唯一在信号处理器中保证安全的输出函数:write()系统调用。

// 错误的做法
void signal_handler(int sig) {printf("Goodbye!\n"); // 危险!可能导致崩溃。exit(0);
}// 正确的做法
void signal_handler(int sig) {// 使用异步信号安全的writeconst char msg[] = "Goodbye!\n";write(STDERR_FILENO, msg, sizeof(msg) - 1);_exit(0); // 在信号处理器中,使用_exit更安全
}

将信号处理器中的所有操作替换为安全版本后,程序在面对中断信号时表现稳定,再也没有出现崩溃或输出异常。


参考资料

AI工具

  • 豆包
  • Deepseek

图书

  • 《Headfirst C》
http://www.jsqmd.com/news/35179/

相关文章:

  • 从容器到云原生:开发者需要掌握的核心思维
  • 从零开始学Flink:实时流处理实战 - 教程
  • 【STM32方案开源】基于STM32的智能语音台灯框架
  • 2025年实验室全钢通风橱订制厂家权威推荐榜单:实验室全钢排风柜/全钢结构步入式通风柜/全钢台式通风柜源头厂家精选
  • flask: 对Flask-SQLAlchemy查询得到的数据遍历处理
  • go 工作区(workspace)模式
  • # [NOIP 2016 提高组] 天天爱跑步 题解
  • 2025年搓管机全套管实力厂家权威推荐榜单:旋挖全套管/全回转钻机全套管/全回转全套管源头厂家精选
  • jmter题目
  • 提高组数学:扩展欧几里得
  • 2025广州人力资源服务推荐榜:精典人才领衔,派遣/外包靠谱公司精选3家
  • 51汇编--外部中断
  • 51汇编--定时器与计数器
  • 2025年杭州工厂外贸代运营公司权威推荐榜单:海外社媒推广/海外社媒营销/外贸推广源头公司精选
  • 51汇编--数码管显示
  • 深入解析:Isaac Lab 2.3深度解析:全身控制与增强遥操作如何重塑机器人学习
  • 51汇编--串口通信
  • 51-OLED显示代码
  • 新定义RD8T36P48点亮LED--汇编
  • AI元人文:还论“物物交换协议”——价值、规则与共识催化
  • 新定义RD8T36P48使用USCI0的TWI功能点亮OLED
  • qsl 2
  • unt
  • html5 canvas 文本渲染
  • 实用指南:东方仙盟修仙(五)赛博科技修仙养老是一种爱好
  • 2025年河北叛逆不听话教育学校权威推荐榜单:不听话矫正机构/早恋矫正学校/孩子早恋管教学校精选
  • node项目架构
  • python调用ffmpeg对截取视频片段,可批量处理
  • 改善睡眠设备哪家专业:2025年最新排行
  • 2025年改善睡眠设备专业推荐排行榜:科技助力健康生活