一、信号通信
信号是 Linux/Unix 中用于异步通知 进程的机制,可处理随机事件(如用户按下Ctrl+C、进程出错等)。
1. 信号的核心工作流程
- 信号产生:由随机事件触发(如用户操作、系统调用、硬件异常)。
- 信号传递:Linux 内核接收信号请求,在进程控制块(PCB)中根据 PID 找到目标进程。
- 信号处理 :目标进程暂停原有工作流程,执行 PCB 中信号对应下标的处理函数(如信号 2 对应
handle2)。 - 恢复执行:信号处理函数执行完毕后,进程回到原有代码继续运行。
2. 核心函数接口
(1)发送信号:kill
#include <signal.h>
#include <sys/types.h>
int kill(pid_t pid, int sig);
- 功能 :向指定 PID 的进程发送编号为
sig的信号。 - 参数 :
pid:目标进程的 PID(特殊值:pid>0指定进程;pid=0同组进程;pid=-1所有有权限的进程;pid<-1组 ID 为|pid|的进程)。sig:信号编号(可通过kill -l查看所有信号,如SIGINT=2、SIGKILL=9)。
- 返回值 :成功返回 0,失败返回 - 1(设置
errno)。
(2)捕获 / 自定义信号处理:signal
#include <signal.h>
// 函数原型(简化版:sighandler_t为函数指针类型)
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
- 功能 :为编号
signum的信号设置处理函数。 - 参数 :
signum:要处理的信号编号。handler:信号处理方式,可选:SIG_DFL:使用默认处理 (如SIGINT默认终止进程)。SIG_IGN:忽略信号 (如忽略SIGINT则Ctrl+C无效)。- 自定义函数指针:执行用户自定义的处理逻辑(函数参数为信号编号)。
- 返回值 :成功返回之前的信号处理函数指针,失败返回
SIG_ERR(设置errno)。
3. 常用信号
| 信号编号 | 信号名 | 触发场景 | 默认处理 |
|---|---|---|---|
| 2 | SIGINT |
用户按下Ctrl+C |
终止进程 |
| 9 | SIGKILL |
强制终止进程 | 终止进程(不可捕获 / 忽略) |
| 15 | SIGTERM |
kill默认发送的信号 |
终止进程 |
| 17 | SIGCHLD |
子进程退出 / 终止 | 忽略 |
二、System V 共享内存
共享内存是 System V 标准提供的 ** 进程间通信(IPC)** 方式,是最快的 IPC 机制(直接操作内存,无数据拷贝)。
1. 核心特性(与管道对比)
| 特性 | 共享内存 | 管道(无名 / 有名) |
|---|---|---|
| 读写权限 | 双方均可读写(双向) | 半双工(无名管道)/ 全双工(有名管道) |
| 阻塞机制 | 无读阻塞、无写阻塞 | 读阻塞(无数据)、写阻塞(缓冲区满) |
| 数据留存 | 数据持久化(不主动删除则保留) | 数据读取后即被销毁 |
| 配套使用 | 需与信号 / 信号量集搭配(实现同步互斥) | 自带阻塞机制,可独立使用 |
| 内存形态 | 连续内存区域(类似字符数组) | 内核缓冲区 |
2. 共享内存的操作流程
申请键值(ftok)→ 创建/获取共享内存(shmget)→ 映射到进程地址空间(shmat)→ 读写操作 → 解除映射(shmdt)→ 删除共享内存(shmctl)
3. 核心函数接口
(1)生成唯一键值:ftok
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
- 功能:通过文件路径和项目 ID 生成唯一的 System V IPC 键值(用于关联共享内存对象)。
- 参数 :
pathname:任意存在且不被删除重建的文件路径(如./test.file)。proj_id:整形数字(通常用 ASCII 单字符,如'a'=97,仅低 8 位有效)。
- 返回值 :成功返回唯一键值(
key_t),失败返回 - 1(设置errno)。
(2)创建 / 获取共享内存:shmget
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
- 功能:向内核申请共享内存对象(创建新对象或获取已有对象)。
- 参数 :
key:由ftok生成的唯一键值(特殊值IPC_PRIVATE:创建私有共享内存,仅父子进程可用)。size:申请的共享内存大小(单位:字节,建议为页大小的整数倍,页大小通常为 4096 字节)。shmflg:权限标志,组合使用:- 八进制权限(如
0664,同文件权限)。 IPC_CREAT:若不存在则创建新共享内存。IPC_EXCL:与IPC_CREAT搭配,若已存在则返回错误(确保创建新对象)。
- 八进制权限(如
- 返回值 :成功返回共享内存 ID(
shmid),失败返回 - 1(设置errno)。
(3)映射共享内存到进程地址空间:shmat
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
- 功能:将内核中的共享内存映射到进程的本地虚拟地址空间。
- 参数 :
shmid:由shmget返回的共享内存 ID。shmaddr:指定映射的本地地址(通常设为NULL,由系统自动分配)。shmflg:映射权限(0:读写;SHM_RDONLY:只读)。
- 返回值 :成功返回映射后的内存地址,失败返回
(void*)-1(设置errno)。
(4)读写共享内存
共享内存映射后可直接通过指针操作,常用函数:
- 字符串操作 :
strcpy、strcat、strcmp(适用于字符串数据)。 - 二进制数据操作 :
memcpy(适用于结构体、数组等二进制数据)。
(5)解除映射:shmdt
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
- 功能:将进程的本地地址与共享内存断开映射关系(并非删除共享内存)。
- 参数 :
shmaddr:shmat返回的映射地址。 - 返回值 :成功返回 0,失败返回 - 1(设置
errno)。
(6)控制 / 删除共享内存:shmctl
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- 功能:修改共享内存属性或删除共享内存对象。
- 参数 :
shmid:共享内存 ID。cmd:操作命令(常用IPC_RMID:删除共享内存对象;IPC_STAT:获取属性;IPC_SET:设置属性)。buf:指向shmid_ds结构体的指针(IPC_RMID时设为NULL即可)。
- 返回值 :成功返回 0,失败返回 - 1(设置
errno)。
3. 常用命令(管理共享内存)
| 命令 | 功能 |
|---|---|
ipcs -a |
查看所有 System V IPC 对象(共享内存、信号量、消息队列) |
ipcs -m |
仅查看共享内存 |
ipcrm -m <shmid> |
删除指定 ID 的共享内存 |