建议收藏!信号和信号量,你真的会了吗?
一句话区别:
- 信号(Signal):通知进程"发生了一件事"(异步通知机制)。
- 信号量(Semaphore):控制多个线程/进程"谁可以使用资源"(同步互斥机制)。
一、信号(Signal)
1. 什么是信号?
信号(Signal)是 Linux 内核向进程发送的一种异步通知机制。
它用于通知进程:
- 用户按下 Ctrl+C
- 子进程退出
- 定时器超时
- 非法访问内存
- 管道断开
可以理解为:
信号 = 中断 + 通知
例如:
Ctrl + C
│
▼
Linux Kernel
│
发送 SIGINT
│
▼
进程收到信号
Kernel(内核)是计算机操作系统最核心的程序,主要负责管理硬件资源、充当软件与硬件的桥梁以及控制系统安全。
2. 信号的特点
- 异步发生
- 不携带大量数据(普通信号只有编号)
- 可以打断程序当前执行流程
- 每个信号都有编号
- 大多数信号可以被捕获(signal/sigaction)
3. 常见信号
| 信号 | 编号 | 含义 |
|---|---|---|
| SIGHUP | 1 | 终端断开 |
| SIGINT | 2 | Ctrl+C |
| SIGQUIT | 3 | Ctrl+\ |
| SIGILL | 4 | 非法指令 |
| SIGABRT | 6 | abort():非正常退出 |
| SIGFPE | 8 | 除零异常 |
| SIGKILL | 9 | 强制结束(不能捕获) |
| SIGSEGV | 11 | 段错误 |
| SIGPIPE | 13 | 管道断开 |
| SIGALRM | 14 | alarm() 定时器 |
| SIGTERM | 15 | 正常结束 |
| SIGCHLD | 17 | 子进程结束 |
| SIGCONT | 18 | 继续运行 |
| SIGSTOP | 19 | 暂停(不能捕获) |
| SIGTSTP | 20 | Ctrl+Z |
查看:
kill -l
4. 信号产生方式
(1)键盘产生
例如:
Ctrl+C
发送:
SIGINT
用户
│
│ Ctrl+C
▼
终端
│
▼
Kernel
│
▼
进程
(2)kill命令
例如:
kill -15 pid
或者
kill -9 pid
(3)系统调用
例如:
kill(pid,SIGUSR1);
或者
raise(SIGINT);
当前进程主动给自己发送一个 SIGINT 信号。
(4)硬件异常
例如:
int a=1/0;
产生:
SIGFPE
访问非法地址:
SIGSEGV
(5)软件条件
例如:
alarm(5);
五秒后:
SIGALRM
5. 信号处理方式
收到信号以后,有三种处理方式:
默认处理
例如:
SIGTERM
默认:
退出程序
忽略
例如:
signal(SIGINT,SIG_IGN);
按 Ctrl+C:
没有反应
捕获
例如:
void handler(int sig)
{
printf("收到信号%d\n",sig);
}
signal(SIGINT,handler);
收到:
SIGINT
执行:
handler()
6. signal()
#include <signal.h>
signal(SIGINT,handler);
作用:
安装一个信号处理函数。
流程:
7. sigaction()
推荐使用。
比 signal() 更安全。
struct sigaction act;
act.sa_handler=handler;
sigaction(SIGINT,&act,NULL);
优势:
- 更稳定
- 可以设置屏蔽信号
- 可以设置更多属性
8. 信号屏蔽
有时候:
不希望现在处理信号。
可以:
先屏蔽
以后再处理
流程:
常见函数:
sigprocmask()
**<font style="color:rgb(34, 34, 34);">sigprocmask</font>** 是用于检查或修改当前线程信号屏蔽字(Signal Mask)的系统调用,其核心作用是控制哪些信号在当前时刻被“阻塞”(即暂时不递送给进程),从而实现对信号处理的精确时序控制。
9. 未决信号(Pending)
收到信号:
并不会马上执行
可能:
Pending
等待解除屏蔽。
流程:
产生信号
│
▼
Pending
│
解除Mask
▼
执行Handler
10. 信号生命周期
二、信号量(Semaphore)
1. 什么是信号量?
信号量(Semaphore)用于:
同步多个线程/进程对共享资源的访问。
它本质上就是:
一个整数
谁拿到资源:
--
释放资源:
++
2. 为什么需要信号量?
例如:
厕所只有3个坑位。
来了10个人。
坑位:3
A ✔
B ✔
C ✔
D 等待
E 等待
...
只有出来一个:
++
等待的人:
--
进入。
3. 信号量分类
二值信号量
只有:
0
1
作用:
类似:
Mutex
计数信号量
例如:
5
表示:
有5个资源
4. P操作 和 V操作
经典名称:
P()
申请资源。
sem_wait()
value--
如果:
value<0
阻塞。
V()
释放资源。
sem_post()
value++
唤醒等待线程。
图解
假设:
Semaphore=3
线程A:
V()
Semaphore=0
↓
线程D 被唤醒
5. Linux POSIX信号量
头文件:
#include <semaphore.h>
创建:
sem_t sem;
初始化:
sem_init(&sem,0,3);
表示:
三个资源
等待:
sem_wait(&sem);
相当于:
P()
释放:
sem_post(&sem);
相当于:
V()
销毁:
sem_destroy(&sem);
6. 工作流程
7. 信号量实现线程同步
例如:
生产者:
生产一个数据
↓
sem_post()
消费者:
sem_wait()
↓
消费数据
流程:
8. 信号量实现互斥
初始化:
Semaphore=1
线程A
wait()
↓
进入临界区
此时:
Semaphore=0
线程B:
wait()
↓
阻塞
线程A:
post()
线程B:
继续执行
9. 信号量 VS 互斥锁
| 对比项 | 信号量 | 互斥锁 |
|---|---|---|
| 本质 | 资源计数器 | 加锁对象 |
| 值 | 可以大于1 | 只能锁/解锁 |
| 可控制资源数 | ✔ | ✘ |
| 谁释放 | 任意线程 | 必须加锁线程 |
| 是否适合同步 | ✔ | 一般 |
| 是否适合互斥 | ✔ | ✔(最佳) |
三、信号 与 信号量 区别
| 项目 | 信号 Signal | 信号量 Semaphore |
|---|---|---|
| 中文 | 信号 | 信号量 |
| 本质 | 异步通知 | 同步机制 |
| 谁发送 | Kernel | 程序员 |
| 是否携带资源 | ✘ | ✔ |
| 是否控制资源 | ✘ | ✔ |
| 是否会中断程序 | ✔ | ✘ |
| 是否用于线程同步 | ✘ | ✔ |
| 是否用于进程通信 | ✔ | ✔ |
四、整体关系图
五、面试高频考点
信号(Signal)
- 什么是信号?有哪些特点?
- 常见信号有哪些?(SIGINT、SIGKILL、SIGTERM、SIGCHLD、SIGSEGV)
- signal() 与 sigaction() 有什么区别?
- SIGKILL 为什么不能捕获?
- SIGSTOP 为什么不能忽略?
- 什么是信号屏蔽(Mask)?
- 什么是未决信号(Pending)?
- kill()、raise()、alarm() 有什么作用?
信号量(Semaphore)
- 什么是 P 操作和 V 操作?
- sem_wait() 和 sem_post() 的作用?
- 二值信号量和计数信号量有什么区别?
- 信号量如何实现线程同步?
- 信号量如何实现互斥?
- 信号量和互斥锁有什么区别?
- 生产者消费者模型为什么适合使用信号量?
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)