Linux 进程开发核心知识总结
一、进程基础概念
1. 进程三要素
- 程序代码:可执行文件(text segment)
- 数据空间:全局变量/堆/栈(data segment)
- 进程控制块(PCB):内核管理结构体,包含:
struct task_struct { pid_t pid; // 进程ID volatile long state; // 进程状态 struct mm_struct *mm; // 内存管理信息 // ... 其他字段 };
2. 进程状态转换
3. 进程地址空间布局
高地址
┌───────────────┐
│ 内核空间 │
├───────────────┤
│ 栈区 │ ← 向下增长
├───────────────┤
│ 堆区 │ ← 向上增长
├───────────────┤
│ 数据段 │
├───────────────┤
│ 代码段 │
└───────────────┘
低地址
二、关键进程操作函数
1. 进程创建
pid_t pid = fork(); // 复制父进程
if (pid == 0) {
// 子进程逻辑
execl("/bin/ls", "ls", "-l", NULL); // 替换为新程序
} else {
// 父进程逻辑
wait(NULL); // 等待子进程结束
}
2. 进程终止
exit(EXIT_SUCCESS); // C库函数,自动刷新缓冲区
_exit(0); // 系统调用,直接终止
3. 进程间通信(IPC)
方式 | 示例代码 | 适用场景 |
---|---|---|
管道 | int fd[2]; pipe(fd); | 父子进程间简单通信 |
共享内存 | shmget(IPC_PRIVATE, 1024, 0666) | 大数据量高速交换 |
信号量 | sem_init(&sem, 0, 1); | 资源互斥访问 |
三、特殊进程解析
1. 僵尸进程(Zombie)
- 成因:子进程终止但父进程未调用
wait
- 危害:占用PCB资源
- 预防:
signal(SIGCHLD, SIG_IGN); // 自动回收子进程
2. 孤儿进程(Orphan)
- 成因:父进程先于子进程终止
- 处理:被
init
进程(PID=1)领养
3. 守护进程(Daemon)
- 创建步骤:
pid = fork(); exit(pid); // 脱离终端 setsid(); // 创建新会话 chdir("/"); // 切换工作目录 umask(0); // 设置文件掩码
四、多线程开发要点
1. 线程与进程对比
维度 | 进程 | 线程 |
---|---|---|
资源分配 | 独立地址空间 | 共享进程资源 |
调度单位 | 内核调度 | 内核调度 |
切换开销 | 大(地址空间切换) | 小(寄存器上下文切换) |
2. 线程同步机制
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&lock);
// 临界区代码
pthread_mutex_unlock(&lock);
3. 协程(Coroutine)
- 特点:用户态调度,轻量级(2KB栈)
- 优势:百万级并发,I/O密集型场景
- 实现:Golang的
goroutine
、C++的libco
五、面试高频问题
1. fork()执行后父子进程的区别
- 返回值:父进程返回子进程PID,子进程返回0
- 内存空间:写时复制(Copy-On-Write)
- 文件描述符:共享打开的文件
2. 如何避免死锁
- 破坏条件:
- 互斥:使用无锁数据结构
- 请求保持:一次性申请所有资源
- 不可剥夺:超时释放资源
- 环路等待:按序加锁
3. 进程上下文切换流程
- 保存当前进程寄存器
- 更新页表基址寄存器
- 加载新进程上下文
- 恢复新进程寄存器
六、开发实践建议
-
内存管理:
- 使用
malloc
/free
管理堆内存 - 避免内存泄漏(Valgrind工具检测)
- 使用
-
性能优化:
- 多进程适合CPU密集型任务
- 多线程适合I/O密集型任务
- 协程适合高并发场景
-
调试技巧:
gdb
调试多线程程序strace
跟踪系统调用perf
分析性能瓶颈
通过以上总结,可系统掌握Linux进程开发的核心知识,结合实际项目进行实践,例如实现一个简单的多进程服务器或线程池,加深对进程调度、内存管理和同步机制的理解。