LWLeon.
LEON / REFERENCE

系统编程:C、进程与并发

集中回顾核心概念、公式和适用条件。

LEON / LEARNING MAP

先看学习路线

按箭头顺序学习。点击一个阶段进入第一节;完整知识框架列出了每一个主题。

  1. 01

    C 对象与数据

    先理解值如何存放,以及指针能在何时访问哪些对象。再用这些规则组织文本、结构和动态数据。

    8 个主题 ↗
  2. 02

    构建与执行程序

    沿着源代码到运行进程的路线,理解预处理、链接、信号和子进程的生命周期。

    5 个主题 ↗
  3. 03

    通信与同步

    先选择数据如何传递,再定义谁能修改共享状态,以及参与者应在什么条件下等待或继续。

    8 个主题 ↗
  4. 04

    扩展与验证

    把正确的程序划分成并行任务。用相同的工作量、可重复的测量和调试证据检验性能与正确性。

    3 个主题 ↗

01 / 表示方式是一份约定

无符号算术按其取值范围进行模运算;有符号溢出是未定义行为。sizeof 以 C 字节为单位返回大小,结果类型是 size_t。自动对象要先初始化再读取。格式化输入输出的转换说明必须与实参的实际类型匹配。

02 / 指针需要有效的生命周期与边界

数组指针运算必须留在同一数组内,或恰好指向末尾之后一个位置;不能解引用这个末尾之后的指针。多维数组通常转换为指向一行的指针,而不是指向指针的指针。

03 / 文本需要足够容量和结束标记

至少预留 strlen+1 个字节。有长度限制的读取也可能只读到一行的一部分。检查转换结果、剩余后缀和取值范围。不能把任意字节序列直接当作有终止符的 C 字符串。

04 / 每次分配都要明确归属

乘法之前先检查 n≤SIZE_MAX/sizeof(*p)。检查分配结果,先初始化再读取。realloc 失败时要保留原指针。所有借用都结束之后,由明确的负责人最终调用一次 free。

05 / 构建程序的各阶段职责不同

预处理展开记号;编译检查一个翻译单元;链接解析外部定义。头文件描述接口。宏可能重复执行带副作用的表达式。头文件保护宏不能阻止不同文件之间出现多个外部定义。

06 / 信号处理函数应尽量简单

优先使用 sigaction 和异步信号安全的操作。一个简单的停止标志可以把清理工作推迟到正常控制流程。检查条件并等待信号时,要用原子地切换屏蔽字并等待的协议。

07 / 进程的生命周期

fork 复制执行状态,普通内存随后各自独立;exec 替换程序映像;waitpid 收集状态。检查每次调用的结果,关闭不用的继承文件描述符,并用配套的宏解释等待状态。

08 / 字节流不等于消息

管道和流式套接字的读取可能拆开一次写入,也可能合并多次写入。定义消息分帧规则,并循环处理部分传输。只有缓冲数据已读完且所有写端都已关闭,管道读取才会遇到 EOF。

09 / 共享存储仍然需要协议

共享内存减少了一部分复制,并没有取消同步要求。不同映射之间用偏移量表示引用。信号量的许可数量跟踪资源;互斥锁保护不变式。明确谁负责初始化、关闭和故障恢复。

10 / 线程需要明确协调

参数必须在线程使用期间一直有效,并正确等待已创建的线程结束。所有冲突访问都要受到保护。条件变量等待要放在检查条件的循环中,并配合对应的互斥锁。volatile 不是通用同步机制。

11 / 防止循环等待

按照稳定的全局顺序获取锁。分析依赖关系时,也要考虑线程等待、条件等待和输入输出。反复调用 trylock 虽然可能不阻塞,却仍可能活锁。仅凭超时不能判断已经死锁。

12 / 比较完成同等工作的耗时

加速比=T₁/Tp。比较的是得到同样且经过验证的结果所需的实际经过时间。划分输出区域的写入归属,依赖完成后再合并结果。考虑串行工作、带宽、负载不均和同步成本。

Leon