赞
踩
管道是一种在操作系统中用于进程间通信的基本机制。它可以让一个进程的输出直接作为另一个进程的输入,实现这两个进程之间的数据传输。下面是管道的一些基本概念:
半双工通信:管道是一种半双工的通信机制,意味着数据只能在一个方向上流动。虽然管道可以同时进行读和写操作,但在任意给定的时间里,数据只能在一个方向上传输。
单向通信:管道是单向通信的,即它只能在一个方向上传输数据。如果需要双向通信,需要创建两个管道,一个用于父进程向子进程传输数据,另一个用于子进程向父进程传输数据。
亲缘关系:管道通常用于具有亲缘关系的进程之间通信,即它们有着共同的父进程。通常情况下,一个管道由一个父进程创建,并在子进程之间传递数据。
内核缓冲区:管道在内核中被实现为一个缓冲区,用于存储数据。这个缓冲区是一个环形队列,可以在其中存储一定数量的数据。当管道满了时,写入操作会被阻塞,直到有空间可用为止。同样,当管道为空时,读取操作也会被阻塞,直到有数据可用为止。
文件描述符:在 Linux 中,管道也被视为一种特殊的文件。每个进程都有一个文件描述符表,用于跟踪打开的文件和管道。当一个管道被创建时,系统会为其分配两个文件描述符,一个用于读取数据,另一个用于写入数据。
匿名管道:匿名管道是最常见的管道类型,它没有名字,只能在具有亲缘关系的进程之间使用。它由 pipe
系统调用创建,返回两个文件描述符,一个用于读取,一个用于写入。
关闭管道:当不再需要一个管道时,应该显式地关闭它。关闭一个管道将释放相关的系统资源,并通知系统不再使用该管道。
针对上述基本概念,提出以下问题:
在 Linux 中,管道是半双工的通信机制,如果对一个管道同时读和写会怎么样?
如果一个进程同时尝试在管道上进行读和写操作,可能会出现以下情况之一:
阻塞:如果一个进程在管道上进行写操作时,而另一个进程正在尝试读取数据,写入操作将被阻塞,直到另一个进程读取了数据为止。同样,如果一个进程在管道上进行读操作时,而另一个进程正在尝试写入数据,读取操作也会被阻塞,直到有数据可用为止。
死锁:如果两个进程同时尝试在管道上进行读和写操作,并且彼此都在等待对方完成操作,可能会导致死锁。例如,一个进程尝试读取数据,但需要等待另一个进程写入数据,而另一个进程同时尝试写入数据,但需要等待第一个进程读取数据。
部分数据:如果一个进程在管道上同时进行读和写操作,可能会导致部分数据的丢失或损坏。这是因为管道是一个先进先出的数据结构,如果同时进行读和写操作,数据可能会被覆盖或丢失。
有名管道和无名管道是什么?怎么建立?
有名管道(Named Pipe)和无名管道(Anonymous Pipe)都是在 Unix 和类 Unix 系统中用于进程间通信的机制,但它们有一些不同之处。
有名管道(Named Pipe):
mkfifo
系统调用或者命令行工具 mkfifo
创建一个有名管道。无名管道(Anonymous Pipe):
pipe()
系统调用来创建一个管道,并获得两个文件描述符,一个用于读取数据,一个用于写入数据。fork()
系统调用创建一个子进程。创建有名管道:
mkfifo my_pipe
或者在 C 语言中使用 mkfifo
函数:
#include <sys/types.h> #include <sys/stat.h> int main() { mkfifo("my_pipe", 0666); // 创建一个有名管道 return 0; }
可以看到创建了一个my_pipe的管道,现在我们
向管道写入数据:
echo "Hello, world!" > my_pipe
使用读取管道:
cat my_pipe
下面将演示多进程间创建有名管道,用于通信的示例
发送端:
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <string.h>
-
- #define FIFO_FILE "my_pipe" // 定义管道文件名
-
- int main() {
- int fd;
- char *message = "Hello, world!"; // 要写入管道的消息
-
- // 创建有名管道
- mkfifo(FIFO_FILE, 0666);
-
- // 打开管道文件
- fd = open(FIFO_FILE, O_WRONLY);
- if (fd == -1) {
- perror("open");
- exit(EXIT_FAILURE);
- }
-
- // 向管道中写入数据
- write(fd, message, strlen(message) + 1);
-
- // 关闭管道文件
- close(fd);
-
- printf("Data sent to the pipe.\n");
-
- return 0;
- }

接收端
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <string.h>
-
- #define FIFO_FILE "my_pipe" // 定义管道文件名
-
- int main() {
- int fd;
- char buffer[1024];
-
- // 打开管道文件
- fd = open(FIFO_FILE, O_RDONLY);
- if (fd == -1) {
- perror("open");
- exit(EXIT_FAILURE);
- }
-
- // 从管道中读取数据
- read(fd, buffer, sizeof(buffer));
- printf("Received message: %s\n", buffer);
-
- // 关闭管道文件
- close(fd);
-
- return 0;
- }

编译运行
此时查看可以看到创建了一个管道
此时运行接收端
接收到消息队列中的消息
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。