一、信号
1. 基本概念
信号是用于通知进程某个事件发生的软中断机制,是进程间异步通信的一种方式。
2. 核心信号与操作
- SIGINT :由
ctrl+c触发,默认功能是终止进程。SIG_IGN:忽略该信号;SIG_DFL:恢复信号的默认行为;signal(信号值, 处理行为):修改信号的处理逻辑,实现信号功能替换。
- kill():用于向进程发送指定信号,主动触发信号机制。
二、进程间通信(IPC)方式
进程间通信核心方式包括:管道、共享内存、消息队列、信号量、套接字,以下重点整理前四类核心机制。
1. 管道
管道是基于文件描述符的半双工通信方式,数据传输遵循先进先出(FIFO),分为有名管道和无名管道两类。
| 特性 | 有名管道 | 无名管道 |
|---|---|---|
| 名称 | 有文件名,存在于文件系统 | 无名称,仅通过文件描述符访问 |
| 进程关系 | 任意有权限的进程 | 仅亲缘进程(父子 / 兄弟) |
| 生命周期 | 随文件系统(需手动删除) | 随进程销毁而销毁 |
| 创建方式 | mkfifo 命令 |
pipe() 系统调用 |
1.1 通用特性与注意事项
- 通信模式:半双工(同一时刻仅能单向传输);
- 数据特性:字节流无边界,若按消息传输需自定义格式(长度 + 数据),避免多读 / 少读;
- 核心问题:
- 管道破裂:读端关闭后写端仍写入,触发
SIGPIPE信号终止写端进程; - 缓冲区阻塞:读空 / 写满会阻塞进程,需通过
fcntl()设置非阻塞属性; - 资源泄漏:进程退出前未关闭描述符,会导致缓冲区数据丢失。
- 管道破裂:读端关闭后写端仍写入,触发
1.2 测试与使用
- 命令行测试:
- 读端持续监听:
while true;do cat < 管道文件;done; - 写端写入:
cat > 管道文件。
- 读端持续监听:
- 代码操作:
- 读管道:使用
read()函数,注意第三个参数不能用初始化的strlen; - 写管道:使用
write()函数向管道文件写入数据。
- 读管道:使用
2. 共享内存
共享内存是最快的 IPC 方式,通过将同一块内存映射到多个进程的地址空间,实现数据直接共享。
2.1 核心函数
| 函数 | 功能 | 关键参数 / 返回值 |
|---|---|---|
shmget() |
创建 / 获取共享内存 | key:唯一标识;size:内存大小(新建填正数,获取填 0);shmflg:IPC_CREAT(创建)+ 权限位;返回值:成功返回标识符,失败返回 - 1 |
shmat() |
将共享内存映射到进程地址空间 | shm_id:shmget返回值;shm_addr:NULL(系统自动分配地址)/ 自定义地址;shmflg:0(读写)/SHM_RDONLY(只读);返回值:映射后的内存地址 |
2.2 操作流程
- 创建共享内存:
shmget(key, size, IPC_CREAT | 0666); - 映射到进程:
shmat(shm_id, NULL, 0); - 进程读写共享内存数据;
- 解除映射(可选):
shmdt(); - 删除共享内存(释放资源):通过
shmctl()设置IPC_RMID。
2.3 练习场景
- 读进程:持续读取共享内存中的数值;
- 写进程:持续向共享内存写入数值。
3. 信号量
信号量用于进程间同步与互斥,本质是受保护的整数计数器,通过原子操作修改值,控制共享资源的访问。
3.1 核心概念
- 原子操作:信号量的加减操作不可中断,避免多进程并发修改导致数据不一致;
- 堵塞机制:信号量值为 0 时,获取该信号量的进程阻塞,直到其他进程释放资源;
- 类型:
- 二值信号量:值为 0/1,实现互斥(类似锁,一次仅一个进程访问);
- 计数信号量:值为非负数,控制多个相同资源的并发访问;
- P/V 原语:
- P 操作(减 1):结果≥0 则进程继续,否则阻塞;
- V 操作(加 1):永远不阻塞,若有阻塞进程则唤醒一个;
- 临界资源:同一时刻仅允许一个进程访问的资源;
- 临界区:访问临界资源的代码段。
3.2 核心函数
| 函数 | 功能 | 关键参数 / 返回值 |
|---|---|---|
semget() |
创建 / 获取信号量集 | key:唯一标识;nsems:信号量个数(新建 / 获取均需 > 0);semflg:IPC_CREAT+ 权限;返回值:成功返回标识符,失败返回 - 1 |
semctl() |
控制信号量集(设置 / 获取 / 删除) | semid:信号量集标识符;semnum:信号量索引(整体操作忽略);cmd:SETVAL(设初始值)/GETVAL(取值)/IPC_RMID(删除);可变参数:union semun(自定义联合体) |
semop() |
执行信号量 P/V 操作 | semid:信号量集标识符;sops:指向sembuf结构体的指针(含sem_num(索引)、sem_op(±1)、sem_flg(SEM_UNDO));nsops:操作数个数 |
3.3 关键结构体 / 联合体
-
联合体
semun(自定义):union semun { int val; // 用于SETVAL(设置信号量值) struct semid_ds *buf; // 用于IPC_STAT/IPC_SET(状态信息) unsigned short *array; // 用于GETALL/SETALL(批量操作) struct seminfo *_buf; // 用于IPC_INFO(系统限制) }; -
结构体
sembuf:struct sembuf { unsigned short sem_num; // 信号量索引 short sem_op; // 操作类型(+1/V操作,-1/P操作) short sem_flg; // 标志位,常用SEM_UNDO(异常退出时撤销修改) };
3.4 操作流程
- 创建信号量集:
semget(key, nsems, IPC_CREAT | 0600); - 设置信号量初始值:
semctl(semid, 0, SETVAL, {.val = 1})(二值信号量); - 执行 P/V 操作:通过
semop()传入sembuf结构体(如sem_op = -1为 P 操作,sem_op = +1为 V 操作); - 释放资源:
semctl(semid, 0, IPC_RMID)(删除信号量集)。
三、补充工具
ipcs:查看系统中 IPC 资源(共享内存、信号量、消息队列);ipcrm:手动删除 IPC 资源(配合ipcs结果清理)。