9.进程间通信
9.进程间通信
- **1. 进程间通信(IPC)概述**
- **2. 无名管道(Pipe)**
- **3. 有名管道(FIFO)**
- **4. 信号通信(Signal)**
- **5. 练习与作业**
- **6. 信号的应用**
- **7. 总结**
1. 进程间通信(IPC)概述
- IPC的分类:
- 古老的通信方式:
- 无名管道(
pipe
)。 - 有名管道(
fifo
)。 - 信号(
signal
)。
- 无名管道(
- IPC对象通信:
- 消息队列(较少使用)。
- 共享内存。
- 信号量集。
- Socket通信:用于网络通信。
- 古老的通信方式:
2. 无名管道(Pipe)
- 特性:
- 只能用于有亲缘关系的进程间通信(如父子进程)。
- 半双工通信模式(单向通信)。
- 数据以队列形式存储,先进先出(FIFO)。
- 数据容量上限为64KB。
- 使用框架:
- 创建管道:
int pipe(int pipefd[2]);
pipefd[0]
:读端。pipefd[1]
:写端。
- 读写管道:
- 读:
read(pipefd[0], buffer, size);
- 写:
write(pipefd[1], buffer, size);
- 读:
- 关闭管道:
close(pipefd[0]); close(pipefd[1]);
- 创建管道:
- 注意事项:
- 管道的创建应在
fork
之前。 - 读端关闭时,写操作会触发
SIGPIPE
信号。 - 写端关闭时,读操作会返回
0
(表示文件结束)。
- 管道的创建应在
3. 有名管道(FIFO)
- 特性:
- 可用于任意进程间通信。
- 在文件系统中可见(通过
mkfifo
创建)。 - 半双工通信模式。
- 使用框架:
- 创建有名管道:
int mkfifo(const char *pathname, mode_t mode);
- 打开有名管道:
int fd_read = open("./fifo", O_RDONLY); int fd_write = open("./fifo", O_WRONLY);
- 读写管道:
- 读:
read(fd_read, buffer, size);
- 写:
write(fd_write, buffer, size);
- 读:
- 关闭管道:
close(fd_read); close(fd_write);
- 卸载管道:
int unlink(const char *pathname);
- 创建有名管道:
4. 信号通信(Signal)
- 特性:
- 异步通信方式。
- 用于进程间发送简单的通知。
- 信号的处理方式:
- 默认处理:系统默认行为(如终止进程)。
- 忽略处理:忽略信号(如
SIG_IGN
)。 - 自定义处理:捕获信号并执行自定义函数。
- 信号注册函数:
typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
handler
:可以是SIG_DFL
(默认)、SIG_IGN
(忽略)或自定义函数。
- 常见信号:
SIGKILL
(9):强制终止进程,不可捕获或忽略。SIGSTOP
(19):暂停进程,不可捕获或忽略。SIGUSR1
(10)和SIGUSR2
(12):用户自定义信号。
5. 练习与作业
- 练习1:设计一个多进程程序,使用无名管道在父子进程间传递任意信息(如数字、字符串)。
- 练习2:验证管道的同步效果,测试读端关闭时写操作的行为,以及写端关闭时读操作的行为。
- 练习3:使用有名管道实现非亲缘关系进程间的通信,支持连续发送数据并在收到
quit
时退出。 - 作业1:封装有名管道的读写函数:
int fifo_read(char *fifoname, void *s, int size); int fifo_write(char *fifoname, void *s, int size);
- 作业2:修改有名管道通信程序,添加信号处理流程,当发送
quit
时,进程A发送信号,进程B收到信号后退出。
6. 信号的应用
- 发送信号:
kill
:向指定进程发送信号。int kill(pid_t pid, int sig);
raise
:向当前进程发送信号。int raise(int sig);
alarm
:设置定时器,定时发送SIGALRM
信号。unsigned int alarm(unsigned int seconds);
- 信号处理:
- 自定义信号处理函数:
void handler(int sig) { // 自定义处理逻辑 }
- 注册信号处理函数:
signal(SIGUSR1, handler);
- 自定义信号处理函数:
7. 总结
- 无名管道:适用于有亲缘关系的进程间通信,数据容量有限。
- 有名管道:适用于任意进程间通信,通过文件系统可见。
- 信号通信:适用于异步通知,支持默认、忽略和自定义处理方式。