一句话区别:

  • 信号(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

Ctrl+C

Ctrl+\\

Ctrl+Z

kill

kill -9

kill -STOP

kill -CONT

fg/bg

除0

非法内存

非法指令

abort

alarm到时

终端关闭

子进程结束

写入断开的管道/Socket

程序运行

收到什么信号?

SIGINT
退出

SIGQUIT
退出+Core

SIGTSTP
暂停

SIGTERM
正常退出

SIGKILL
强制退出

SIGSTOP
强制暂停

SIGCONT
继续

SIGFPE

SIGSEGV

SIGILL

SIGABRT

SIGALRM

SIGHUP

SIGCHLD

SIGPIPE

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. 信号处理方式

收到信号以后,有三种处理方式:

SIG_DFL

SIG_IGN

User Handler

收到信号

查询信号处理动作

默认处理
Default

忽略
Ignore

用户捕获
Catch

默认处理

例如:

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);

作用:

安装一个信号处理函数。

流程:

收到 SIGINT

Kernel: 检查处理动作

是否为自定义 handler?

Kernel: 保存用户态上下文

Kernel: 切换到信号栈

执行 handler

执行 sigreturn 系统调用

Kernel: 恢复用户态上下文

返回程序继续执行

执行默认动作/忽略

7. sigaction()

推荐使用。

比 signal() 更安全。

struct sigaction act;

act.sa_handler=handler;

sigaction(SIGINT,&act,NULL);

优势:

  • 更稳定
  • 可以设置屏蔽信号
  • 可以设置更多属性

8. 信号屏蔽

有时候:

不希望现在处理信号。

可以:

先屏蔽
以后再处理

流程:

收到 SIGINT

加入Pending

解除屏蔽

执行handler

常见函数:

sigprocmask()

**<font style="color:rgb(34, 34, 34);">sigprocmask</font>** 是用于检查或修改当前线程信号屏蔽字(Signal Mask)的系统调用,其核心作用是控制哪些信号在当前时刻被“阻塞”(即暂时不递送给进程),从而实现对信号处理的精确时序控制。

9. 未决信号(Pending)

收到信号:

并不会马上执行

可能:

Pending

等待解除屏蔽。

流程:

产生信号
    │
    ▼
Pending
    │
解除Mask
    ▼
执行Handler

10. 信号生命周期

产生 Signal

Pending

是否屏蔽?

Delivery

Handler

二、信号量(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
线程D 线程C 线程B 线程A Semaphore (初始值=2) 线程D 线程C 线程B 线程A Semaphore (初始值=2) 初始值 = 2 ✅ 获取成功,继续执行 ✅ 获取成功,继续执行 ⏳ 信号量 < 0,进入等待队列 ⏳ 信号量 < 0,进入等待队列 当前状态:2个线程运行,2个线程等待 P() 值: 2 → 1 P() 值: 1 → 0 P() 值: 0 → -1 P() 值: -1 → -2

线程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. 工作流程

Yes

No

线程请求资源

Semaphore > 0 ?

sem--

进入临界区

阻塞等待

sem_post

sem++

唤醒等待线程

7. 信号量实现线程同步

例如:

生产者:

生产一个数据
↓

sem_post()

消费者:

sem_wait()

↓

消费数据

流程:

Producer

Buffer

sem_post

Semaphore

Consumer

sem_wait

8. 信号量实现互斥

初始化:

Semaphore=1
线程A

wait()

↓

进入临界区

此时:

Semaphore=0

线程B:

wait()

↓

阻塞

线程A:

post()

线程B:

继续执行

9. 信号量 VS 互斥锁

对比项 信号量 互斥锁
本质 资源计数器 加锁对象
可以大于1 只能锁/解锁
可控制资源数
谁释放 任意线程 必须加锁线程
是否适合同步 一般
是否适合互斥 ✔(最佳)

三、信号 与 信号量 区别

项目 信号 Signal 信号量 Semaphore
中文 信号 信号量
本质 异步通知 同步机制
谁发送 Kernel 程序员
是否携带资源
是否控制资源
是否会中断程序
是否用于线程同步
是否用于进程通信

四、整体关系图

Linux 进程/线程同步与通信

Signal 信号

Semaphore 信号量

本质

异步通知

软件中断

产生方式

kill

raise

alarm

Ctrl+C

分类

不可靠信号

可靠信号

处理方式

默认

忽略

捕获

常用API

signal

sigaction

kill

sigprocmask

本质

同步

互斥

资源计数

类型

无名信号量

有名信号量

P/V操作

sem_wait

sem_post

sem_trywait

常用API

sem_init

sem_destroy

sem_open

sem_close

sem_unlink

应用

线程同步

进程同步

生产者消费者

资源池

五、面试高频考点

信号(Signal)

  • 什么是信号?有哪些特点?
  • 常见信号有哪些?(SIGINT、SIGKILL、SIGTERM、SIGCHLD、SIGSEGV)
  • signal() 与 sigaction() 有什么区别?
  • SIGKILL 为什么不能捕获?
  • SIGSTOP 为什么不能忽略?
  • 什么是信号屏蔽(Mask)?
  • 什么是未决信号(Pending)?
  • kill()、raise()、alarm() 有什么作用?

信号量(Semaphore)

  • 什么是 P 操作和 V 操作?
  • sem_wait() 和 sem_post() 的作用?
  • 二值信号量和计数信号量有什么区别?
  • 信号量如何实现线程同步?
  • 信号量如何实现互斥?
  • 信号量和互斥锁有什么区别?
  • 生产者消费者模型为什么适合使用信号量?
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐