Linux系统编程|进程间通信IPC全套详解(1)(管道、信号)
一、管道通信
管道本质是内核开辟的一块缓冲区,遵循FIFO先进先出规则,分为无名管道pipe和有名管道FIFO(mkfifo)。
1.1 无名管道(匿名管道 pipe)
无名管道只能用于有亲缘关系进程之间通信(父子、兄弟进程)。
原理:父进程调用`pipe()`创建管道得到两个文件描述符,fork创建子进程后,子进程复制父进程文件描述符,父子进程就可以操作同一组管道fd完成数据传输。
函数原型
#include <unistd.h>
int pipe(int pipefd[2]);
- pipefd[0]:管道读端,使用read读取数据
- pipefd[1]:管道写端,使用write写入数据
- 返回值:成功返回0;失败返回1
管道核心特性
1. 半双工单向通信;数据只能单向流动;
2. 缓冲区默认大小64K;
3. 写阻塞:管道写满,write会阻塞;
4. 读阻塞:管道为空,read会阻塞;
5. 读返回0:管道写端全部关闭,read返回0,代表读到末尾;
6. 管道破裂SIGPIPE:管道读端全部关闭,继续写管道,会产生SIGPIPE信号,进程默认直接退出。
简单示例逻辑:父进程创建pipe,fork子进程;父关闭读端往pipefd[1]写数据;子关闭写端从pipefd[0]读数据。
1.2 有名管道 FIFO(mkfifo)
无名管道局限于亲缘进程,有名管道解决这个问题,可以用于本机任意两个进程通信。
它会在文件系统生成一个特殊管道文件,不同进程通过open打开这个文件,就可以完成通信。
函数原型
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
- pathname:管道文件路径
- mode:文件权限,例如0664
- 返回值:成功0,失败1
创建完成后,就像普通文件一样使用open/read/write/close操作。
注意:打开FIFO会发生阻塞:一个进程以读打开,会阻塞等待另一个进程以写打开;反之亦然。
无名管道 vs 有名管道对比
|
特性 |
无名管道 pipe |
有名管道 FIFO |
|
适用进程 |
仅父子 / 兄弟亲缘进程 |
本机任意进程 |
|
文件系统 |
无实体文件,内核缓冲区 |
生成 FIFO 特殊文件 |
|
创建方式 |
pipe() |
mkfifo() |
|
生命周期 |
进程全部退出自动销毁 |
文件存在,可手动 rm 删除 |
二、信号 Signal —— 异步软中断通知
信号是Linux提供的异步通知机制,信号本身不携带大量业务数据,仅仅用来通知进程发生某个事件,相当于软件层面的中断。
常见信号列表
|
信号编号 |
宏名称 |
作用说明 |
|
2 |
SIGINT |
Ctrl+C,中断进程 |
|
3 |
SIGQUIT |
Ctrl+\,进程退出 |
|
9 |
SIGKILL |
强制杀死进程,不能捕获、不能忽略 |
|
11 |
SIGSEGV |
段错误,访问非法内存触发 |
|
13 |
SIGPIPE |
管道破裂,写已经没有读端的管道 |
|
14 |
SIGALRM |
alarm 定时超时信号 |
|
17 |
SIGCHLD |
子进程退出时,发送给父进程,用来回收僵尸进程 |
|
19 |
SIGSTOP |
强制暂停进程,不可捕获忽略 |
|
10/12 |
SIGUSR1、SIGUSR2 |
用户自定义预留信号,业务自己使用 |
信号三种处理方式
进程收到信号,可以选择下面三种处理:
1. SIG_IGN 忽略:收到信号直接无视,不做处理
2. SIG_DFL 默认处理:操作系统默认行为(终止、暂停、打印core转储等)
3. 捕获信号:注册自定义处理函数,收到信号执行自己写的回调函数
signal注册信号函数
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
- signum:要处理的信号编号
- handler:处理方式,SIG_IGN / SIG_DFL / 自定义回调函数地址
- 返回值:成功返回旧处理函数;失败返回SIG_ERR
注意:signal函数接口简单,但部分行为在不同版本Linux存在差异;正式项目推荐使用sigaction。
简单示例:捕获Ctrl+C信号,不直接杀死程序
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sig_handler(int sig)
{
printf("收到信号 %d,程序不会直接退出\n", sig);
}
int main(void)
{
signal(SIGINT, sig_handler);
while(1)
{
sleep(1);
printf("程序运行中...\n");
}
return 0;
}
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)