目录
1. 管道(Pipe)
- 适用场景:用于具有亲缘关系的进程间通信,如父子进程。
- 优点:实现简单,使用方便。
- 提出背景:早期操作系统中,父子进程间需要简单通信机制。
- 时间顺序:是最早的进程间通信方式之一。
- 通信原理:通过内核缓冲区实现数据传输,数据只能单向流动,若需双向通信需建立两个管道。
- 效率:效率中等,数据量大时可能阻塞。
- 传递的消息:无格式字节流。
匿名管道(Anonymous Pipe)
- 定义:匿名管道是一种简单的进程间通信机制,主要用于父子进程之间的单向通信。
- 创建方式:通过 pipe 系统调用创建。
- 适用场景:仅限于具有亲缘关系的进程(如父子进程)。
- 提出背景:作为早期操作系统中简单高效的父子进程通信机制。
命名管道(FIFO)
- 定义:命名管道是一种特殊的文件,通过文件系统中的路径名标识,允许不相关的进程进行通信。
- 创建方式:通过 mkfifo 函数创建。
- 适用场景:无亲缘关系的进程间通信。
- 优点:允许非亲缘进程通信。
- 提出背景:为解决匿名管道只能用于亲缘进程的限制。
- 时间顺序:在匿名管道之后。
- 通信原理:通过文件系统中的路径名访问,数据按先进先出顺序传输。
- 效率:效率中等,比匿名管道稍低。
- 传递的消息:无格式字节流。
示例代码
父子进程之间传递数据,例如,父进程向子进程发送字符串。 父进程通过 pipe 创建管道、父进程向管道的写端写入数据、子进程从管道的读端读取数据。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main() {
int pipefds[2];
pid_t pid;
char message[] = "Hello from parent!";
char buffer[80];
// 创建管道
if (pipe(pipefds) == -1) {
perror("pipe");
exit(1);
}
// 创建子进程
pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
if (pid == 0) {
// 子进程
close(pipefds[1]); // 关闭写端
read(pipefds[0], buffer, sizeof(buffer)); // 从管道读取数据
printf("Child received: %s\n", buffer);
close(pipefds[0]);
} else {
// 父进程
close(pipefds[0]); // 关闭读端
write(pipefds[1], message, strlen(message)); // 向管道写入数据
close(pipefds[1]);
wait(NULL); // 等待子进程结束
}
return 0;
}
2. 消息队列(Message Queue)
- 适用场景:多个进程间传递结构化数据,支持异步通信。
- 优点:传递结构化数据,支持异步通信。
- 提出背景:克服信号传递信息量少、管道只能承载无格式字节流的缺点。
- 时间顺序:在管道之后。
- 通信原理:消息存储在内核中,进程通过系统调用发送和接收消息。
- 效率:效率中等,数据拷贝较多。
- 传递的消息:结构化数据,每条消息有类型标识。
示例代码
多个进程之间传递结构化消息,例如,生产者向消费者发送消息。 使用 msgget 创建消息队列、父进程通过 msgsnd 发送消息、子进程通过 msgrcv 接收消息。
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <unistd.h>
struct msg_buffer {
long msg_type;
char msg_text[80];
};
int main()