扁平化风格 网站传奇游戏代理0加盟费
信号(Signal)
(一)本质与核心价值
信号是 Linux 系统中进程间异步通信的“软中断”机制,核心解决:
- 进程控制:如终止、暂停、恢复进程(
SIGINT/SIGSTOP/SIGCONT)。 - 异常处理:捕获非法操作(
SIGSEGV段错误、SIGPIPE管道破裂)。 - 异步通知:子进程结束通知父进程(
SIGCHLD)、定时任务触发(SIGALRM)等。
特点:异步性(接收方无法预测信号何时到达)、抢占性(打断当前代码流优先处理信号)。
(二)系统信号全量清单(kill -l 输出)
通过 kill -l 可查看系统支持的 64 个信号(不同系统可能有差异),按功能分类关键信号:
1. 常用基础信号(1~31 为非实时信号,32~64 为实时信号 SIGRTMIN~SIGRTMAX)
| 信号编号 | 信号名 | 触发场景/默认行为 | 关键特性 |
|---|---|---|---|
| 1 | SIGHUP | 终端断开、进程组领导权变化 | 常用于“重启配置”(如 nginx 重载) |
| 2 | SIGINT | Ctrl + c 触发 | 中断进程,默认终止 |
| 3 | SIGQUIT | Ctrl + \ 触发 | 终止进程并生成 core dump |
| 4 | SIGILL | 非法指令执行(如二进制文件格式错误) | 进程崩溃,默认终止 |
| 5 | SIGTRAP | 调试陷阱(如 gdb 断点触发) | 调试专用,默认终止 |
| 6 | SIGABRT | 进程主动调用 abort() | 强制终止并生成 core dump |
| 7 | SIGBUS | 总线错误(如内存对齐违规) | 进程崩溃,默认终止 |
| 8 | SIGFPE | 浮点运算错误(除零、溢出等) | 进程崩溃,默认终止 |
| 9 | SIGKILL | kill -9 强制发送 | 强制终止,无法被捕获/忽略 |
| 10 | SIGUSR1 | 用户自定义信号 | 需编程捕获,实现自定义逻辑 |
| 11 | SIGSEGV | 非法内存访问(越界、空指针) | 进程崩溃(段错误),默认终止 |
| 12 | SIGUSR2 | 用户自定义信号 | 需编程捕获,实现自定义逻辑 |
| 13 | SIGPIPE | 管道写端关闭后仍写操作 | 进程崩溃(管道破裂),默认终止 |
| 14 | SIGALRM | alarm() 定时触发或系统定时任务 | 定时通知,默认终止 |
| 15 | SIGTERM | kill 默认信号(kill -15) | 优雅终止进程,可捕获处理 |
| 16 | SIGSTKFLT | 栈溢出(老式架构,现代系统少用) | 进程崩溃,默认终止 |
| 17 | SIGCHLD | 子进程退出、暂停或继续 | 通知父进程回收子进程 |
| 18 | SIGCONT | 显式发送或作业控制恢复 | 恢复暂停态进程执行 |
| 19 | SIGSTOP | 强制暂停(kill -19) | 暂停进程,无法被捕获/忽略 |
| 20 | SIGTSTP | Ctrl + z 触发 | 暂停进程(终端停止信号) |
| 21 | SIGTTIN | 后台进程读终端 | 暂停进程,默认终止 |
| 22 | SIGTTOU | 后台进程写终端 | 暂停进程,默认终止 |
| 23 | SIGURG | 套接字紧急数据到达 | 通知进程处理紧急数据 |
| 24 | SIGXCPU | 进程 CPU 时间超过限制 | 进程崩溃,默认终止 |
| 25 | SIGXFSZ | 文件大小超过系统限制 | 进程崩溃,默认终止 |
| 26 | SIGVTALRM | 虚拟时钟定时(按进程 CPU 时间计时) | 定时通知,默认终止 |
| 27 | SIGPROF | 剖析时钟定时(含内核时间) | 性能分析工具常用 |
| 28 | SIGWINCH | 终端窗口大小变化 | 通知进程调整输出格式 |
| 29 | SIGIO | 异步 I/O 事件通知 | 高性能 I/O 模型(如 epoll) |
| 30 | SIGPWR | 电源状态变化(如电池低电量、断电) | 通知进程处理电源事件 |
| 31 | SIGSYS | 系统调用参数错误(如调用未实现的系统调用) | 进程崩溃,默认终止 |
2. 实时信号(SIGRTMIN ~ SIGRTMAX)
- 编号:
32~64(具体数量因系统而异,如SIGRTMIN可能是34,需kill -l确认)。 - 特点:高优先级(比普通信号先处理)、可排队(避免信号丢失)、用户可控(常用于实时系统、低延迟通知场景)。
(三)信号处理流程与编程
1. 信号处理方式
进程对信号有三种响应策略:
- 缺省(
SIG_DFL):按系统默认行为处理(如SIGINT默认终止进程)。 - 忽略(
SIG_IGN):不处理信号(如忽略SIGCHLD需自己回收子进程)。 - 捕获(自定义函数):注册回调函数,信号触发时执行自定义逻辑。
2. 核心函数:signal
- 头文件:
#include <signal.h> - 原型:
typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); - 作用:注册信号处理函数(绑定信号
signum与处理逻辑handler)。 - 参数:
signum:信号编号(如SIGINT)。handler:处理方式(SIG_IGN/SIG_DFL或自定义函数地址)。
- 返回值:
- 成功:返回之前的信号处理函数(首次注册返回
SIG_DFL)。 - 失败:返回
SIG_ERR(需检查errno)。
- 成功:返回之前的信号处理函数(首次注册返回
示例:捕获 SIGINT 并自定义处理:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>void handle_sigint(int signum) {printf("捕获到信号:%d(SIGINT),进程继续运行...\n", signum);
}int main() {// 注册信号处理函数if (signal(SIGINT, handle_sigint) == SIG_ERR) {perror("signal");return 1;}printf("进程启动,按 Ctrl + c 测试信号捕获...\n");while (1) {sleep(1); // 模拟业务逻辑}return 0;
}
(四)信号发送与控制
1. 命令行发送信号:kill 命令
- 语法:
kill -[信号编号/名称] 进程PID- 示例:
kill -9 1234:强制终止 PID 为1234的进程(发送SIGKILL)。kill -SIGUSR1 5678:给 PID5678发送SIGUSR1信号。
- 示例:
2. 编程发送信号函数
| 函数名 | 作用 | 关键参数 | 示例(简化) |
|---|---|---|---|
kill | 给指定进程发信号 | pid_t pid, int sig | kill(1234, SIGINT); |
raise | 给自己所在进程发信号 | int sig | raise(SIGALRM); |
alarm | 定时发送 SIGALRM 信号 | unsigned int seconds | alarm(5);(5 秒后发 SIGALRM) |
pause | 挂起进程,等待信号唤醒 | - | pause();(被信号打断后继续) |
共享内存(Shared Memory)
(一)核心价值
进程间通信(IPC)效率最高的方式,原理:
- 内核开辟一块共享内存区域,多个进程通过内存映射将其映射到自己的虚拟地址空间。
- 进程直接读写内存地址完成数据交换,跳过“内核-用户空间”的拷贝(如管道、消息队列需两次拷贝)。
适合场景:大数据量、低延迟的进程协作(如多进程并行计算、游戏服务器进程间同步)。
(二)操作流程与函数(6 步完整周期)
1. 创建 IPC Key:ftok
- 头文件:
#include <sys/types.h>、#include <sys/ipc.h> - 原型:
key_t ftok(const char *pathname, int proj_id); - 作用:生成唯一的 IPC 键值,用于标识共享内存(不同进程需用相同
pathname和proj_id生成相同 key)。 - 参数:
pathname:存在的文件路径(如"/tmp"),建议用固定文件避免冲突。proj_id:项目 ID(1~255 的整数,如'A'等价于65)。
- 返回值:
- 成功:返回
key_t类型的键值。 - 失败:返回
-1(检查errno,如文件不存在、权限不足)。
- 成功:返回
2. 创建共享内存:shmget
- 头文件:
#include <sys/types.h>、#include <sys/shm.h> - 原型:
int shmget(key_t key, size_t size, int shmflg); - 作用:向内核申请共享内存,返回 共享内存 ID(后续操作的标识)。
- 参数:
key:ftok生成的键值。size:共享内存大小(字节),自动对齐为系统页大小(如4096字节的整数倍)。shmflg:权限标志(如IPC_CREAT | 0664,IPC_CREAT表示不存在则创建,0664是权限)。
- 返回值:
- 成功:返回共享内存 ID(非负整数)。
- 失败:返回
-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:权限(SHM_RDONLY只读;0读写,需配合内存权限)。
- 返回值:
- 成功:返回映射后的内存首地址(
void *类型)。 - 失败:返回
(void *)-1(检查errno,如权限不足)。
- 成功:返回映射后的内存首地址(
4. 读写共享内存
- 直接通过
shmat返回的指针操作内存,如:char *shm_ptr = shmat(shmid, NULL, 0); if (shm_ptr != (void *)-1) { // 写数据 sprintf(shm_ptr, "Hello, Shared Memory!"); // 读数据 printf("共享内存内容:%s\n", shm_ptr); }
5. 解除映射:shmdt
- 头文件:
#include <sys/types.h>、#include <sys/shm.h> - 原型:
int shmdt(const void *shmaddr); - 作用:断开共享内存与进程虚拟地址空间的映射(不销毁共享内存,仅解除当前进程的关联)。
- 参数:
shmaddr:shmat返回的内存首地址。 - 返回值:
- 成功:返回
0。 - 失败:返回
-1(检查errno,如地址无效)。
- 成功:返回
6. 销毁共享内存:shmctl
- 头文件:
#include <sys/types.h>、#include <sys/shm.h> - 原型:
int shmctl(int shmid, int cmd, struct shmid_ds *buf); - 作用:控制共享内存(如销毁、查询状态)。
- 参数:
shmid:共享内存 ID。cmd:操作指令(IPC_RMID表示标记销毁,需所有进程解除映射后实际释放)。buf:填NULL(销毁时无需额外参数)。
- 返回值:
- 成功:返回
0。 - 失败:返回
-1(检查errno,如权限不足)。
- 成功:返回
(三)命令行工具
- 查看 IPC 资源:
ipcs -a(查看共享内存、信号量、消息队列等)。 - 删除共享内存:
ipcrm -m shmid:通过 ID 删除(如ipcrm -m 1234)。ipcrm -M shmkey:通过ftok生成的 key 删除(如ipcrm -M 0x12345678)。
