一、信号 signal
信号是内核和应用程序之间通信的机制,属于异步通知。进程收到信号,可以选择:默认处理、忽略信号、捕捉信号自定义回调函数。
常见信号速查表
| 信号 | 编号 | 触发来源 | 说明 |
|---|---|---|---|
SIGINT |
2 | Ctrl + c |
终端中断,终止程序 |
SIGQUIT |
3 | Ctrl + \ |
退出程序,会生成core转储文件 |
SIGKILL |
9 | kill -9 | 强制杀死进程,不能捕捉、不能忽略 |
SIGSEGV |
11 | 程序异常 | 段错误,访问非法内存 |
SIGPIPE |
13 | 管道 | 管道破裂,向没有读端的管道写数据 |
SIGALRM |
14 | alarm函数 | 定时时间到产生闹钟信号 |
SIGCHLD |
17 | 子进程 | 子进程退出,通知父进程 |
SIGCONT |
18 | 系统 | 恢复被暂停的进程继续运行 |
SIGSTOP |
19 | Ctrl+z |
暂停进程,不能捕捉、不能忽略 |
⚠ 重点考点:9号SIGKILL、19号SIGSTOP,无法被捕捉、无法被忽略。
信号处理函数 signal
c
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
- 参数1
signum:信号编号 - 参数2
handler三种选择:SIG_IGN:忽略该信号SIG_DFL:系统默认处理方式- 自定义函数指针:捕捉信号,执行回调函数
- 返回值:成功返回上一次注册的处理函数;失败返回
SIG_ERR
配套工具函数
- pause()
c
int pause(void);
功能:让进程睡眠阻塞,直到收到信号被唤醒。
- alarm()闹钟
c
unsigned int alarm(unsigned int seconds);
seconds秒之后,内核给当前进程发送SIGALRM闹钟信号。
二、进程间通信 IPC
Linux常见IPC方式:
- 管道(无名管道、有名管道FIFO)
- 信号
- 消息队列
- 共享内存
- 信号量
1. 无名管道 pipe
无名管道:只适用于有亲缘关系进程通信(父子进程),内核开辟缓冲区,没有实体磁盘文件。
c
int pipe(int pipefd[2]);
pipefd[0]:管道读文件描述符pipefd[1]:管道写文件描述符- 返回:成功返回0;失败返回-1
管道行为特性(考试高频)
-
管道有写端
- 缓冲区有数据:read直接读出数据
- 缓冲区无数据:read阻塞等待,直到写入数据
-
管道没有写端(全部写端close)
- 缓冲区有数据:正常读完
- 缓冲区为空:read返回0,结束,不阻塞
-
管道有读端
- 管道没写满,write直接写入
- 管道写满,write阻塞,等待读端取走数据
-
管道没有读端(全部读端close)
- 调用write写数据 → 产生
SIGPIPE管道破裂信号,进程直接退出。
- 调用write写数据 → 产生
无名管道单向通信;父子进程各保留一端,关闭不需要的fd。
2. 有名管道 FIFO mkfifo
有名管道:无亲缘关系进程之间也可以通信,磁盘上存在管道文件,但是数据仍然存放内核缓冲区,磁盘文件只起标识作用。
c
int mkfifo(const char *pathname, mode_t mode);
pathname:管道文件路径mode:文件权限- 返回:成功0,失败-1
特性:open打开FIFO的时候,读端、写端必须同时到位,否则阻塞等待对端打开 。
只有读打开,没有写打开:读端阻塞;只有写打开没有读打开:写端阻塞。
三、无名管道 vs 有名管道对比
| 无名管道 pipe | 有名管道 FIFO | |
|---|---|---|
| 通信进程 | 仅限亲缘进程(父子) | 任意进程,无关进程也可以 |
| 磁盘文件 | 无实体文件 | 磁盘存在fifo特殊文件 |
| 创建方式 | pipe() | mkfifo() |
| open打开 | 不需要open,直接pipe拿到fd | 需要open打开管道文件 |
| 打开阻塞 | 不会出现open阻塞 | 单独打开读或者写会阻塞 |
四、信号与管道易错考点总结
- SIGKILL(9)、SIGSTOP(19),不能捕捉、不能忽略。
- Ctrl+C → SIGINT;Ctrl+\ → SIGQUIT;Ctrl+Z → SIGTSTP。
- 管道没有读端,write产生SIGPIPE信号,程序崩溃。
- 无名管道只能父子进程;FIFO有名管道任意进程。
- FIFO打开必须读写两端同时存在,否则open阻塞。
- SIGCHLD:子进程退出通知父进程,用来处理僵尸进程。
编译提示
信号程序普通gcc编译;管道代码同样直接gcc编译,不需要额外库。