5.2 Linux 应用开发 进程(二)
一、管道通信(Pipe、FIFO)
1. 无名管道(Pipe)
(1)核心特性:
- 本质:一种特殊的文件,由队列实现,只能用
pipe()函数创建,不能用open()打开;在文件系统中无文件名、无文件节点,因此叫“无名”管道。 - 适用场景:只能用于有亲缘关系的进程间通信(如父子进程),因为它没有文件系统节点,无法被其他进程打开。
- 半双工通信:同一时间只能单向传输数据,一端读、一端写。
(2)核心函数:
int pipe(int fd[2]); // fd[2] 用于保存文件描述符: // fd[0]:读管道(从管道读取数据) // fd[1]:写管道(向管道写入数据) // 返回值:创建成功返回0,创建失败返回-1。
(3)读写特性:
1) 读管道(read())
- 管道中无数据时:
若管道写端被全部关闭:read()返回0(读到 EOF);
若管道写端未全部关闭:read()阻塞等待,直到有数据写入。
- 管道中有数据时:
read()返回实际读到的字节数。
2) 写管道(write())
- 管道读端全部关闭:进程会异常终止(收到
SIGPIPE信号); - 管道读端未全部关闭:
管道已满(默认大小64KB = 65536字节):write()阻塞等待
管道未满:write()将数据写入,返回实际写入的字节数。
(4)补充说明:
- 无名管道本质是一段内存缓冲区(队列形式),数据读完后就会从管道中清除,无法重复读取。
fd是两个文件描述符,子进程会继承父进程的文件描述符表;虽然父子进程的fd变量是分离的,但背后指向的文件(管道)是同一个。
(5)使用示例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main() {
int fd[2]; // fd[0]读端,fd[1]写端
pid_t pid;
char buf[1024];
const char *msg = "Hello from parent process!";
// 1. 创建无名管道
if (pipe(fd) == -1) {
perror("pipe create failed");
exit(EXIT_FAILURE);
}
// 2. 创建子进程
pid = fork();
if (pid == -1) {
perror("fork failed");
exit(EXIT_FAILURE);
}
// 3. 子进程:从管道读数据
if (pid == 0) {
close(fd[1]); // 子进程不需要写,关闭写端(必须!避免阻塞)
// 读取管道数据
ssize_t len = read(fd[0], buf, sizeof(buf)-1);
if (len == -1) {
perror("child read failed");
exit(EXIT_FAILURE);
} else if (len == 0) {
printf("Child: pipe write end closed, no data\n");
} else {
buf[len] = '\0';
printf("Child received: %s\n", buf);
}
close(fd[0]); // 读完关闭读端
exit(EXIT_SUCCESS);
}
// 4. 父进程:向管道写数据
else {
close(fd[0]); // 父进程不需要读,关闭读端(必须!)
// 向管道写入数据
ssize_t len = write(fd[1], msg, strlen(msg));
if (len == -1) {
perror("parent write failed");
exit(EXIT_FAILURE);
}
printf("Parent sent: %s\n", msg);
close(fd[1]); // 写完关闭写端,让子进程read不再阻塞
wait(NULL); // 等待子进程退出,避免僵尸进程
}
return 0;
}
2. 有名管道(FIFO)
(1)核心特性:
- 适用场景:支持非亲缘关系的进程间通信,因为创建的有名管道在文件系统中可见(是一个特殊的管道文件),可被任意进程通过文件名打开。
- 本质:是一个存在于文件系统中的特殊管道文件,数据实际存放在内存中,不占用磁盘空间。
- 半双工通信:同一时间只能单向传输数据。
- 其他特性:遵循先进先出(FIFO)原则;不支持
lseek()文件定位(只能顺序读写);支持标准文件 I/O 操作。
(2)核心函数:
int mkfifo(const char *filename, mode_t mode); // filename:要创建的有名管道文件的路径 / 名称 // mode:文件权限(如0666,需结合umask生效) // 返回值:创建成功返回0,失败返回-1 // 作用:创建一个先进先出的特殊管道文件,只需在一个进程中创建,其他进程直接通过文件名正常读写即可。
(3)读写特性:
- 读端、写端的阻塞情况与无名管道(Pipe)完全一致:
读空且写端未关:读阻塞;读空且写端全关:read( ) 返回 0;
写满且读端未关:写阻塞;读端全关:写进程异常终止。
(4)使用示例:
// 写进程 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
C++/嵌入式开发 秋招面经 文章被收录于专栏
一名985硕,在25年秋招中斩获多个C++/嵌入式开发Offer。本专栏将分享我的面经,涵盖C/C++、操作系统、计算机网络、ARM体系与架构、Linux应用/驱动开发、Qt、通信协议及开发工具链等核心内容。

查看14道真题和解析