先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题
一 管道分类
类型 | 特点 |
---|---|
无名管道 | 在文件系统中没有文件节点 |
有名管道 | 在文件系统中有文件节点 |
– | – |
1.1 特点
(1)管道实际上就是一个单向队列,在两端可以进行读写操作,它是一个特殊的文件,所以无法使用简单open函数创建,我们需要pipe函数来创建
创建函数 pipe
函数形式: int pipe(int fd[2])
功能: 创建管道,为系统调用;头文件 unistd.h
参数: 得到文件描述符,有两个文件描述符,分别是fd[0]和fd[1],管道有一个读端
fd[0]和一个写端fd[1]
返回值: 0表示成功;1表示失败
读写函数: write read
关闭函数: close
(2)管道是创建在内存中的,进程结束,空间释放,管道就不存在了;
(3)管道中的东西读完了就删除了(而常用的open函数创建的文件读了之后,内容仍然存在)
(4)如果管道中没有东西可读,则会阻塞
(5)可以写的管道空间最多是 65536
二 无名管道示例代码
- 创建一个子进程
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>
#include "sys/types.h"
int main()
{
pid_t pid;
pid = fork();
if (pid == 0) { // child process
int i = 0;
for (i = 0; i < 5; i++) {
usleep(100);
printf("this is child process i=%d\n", i);
}
}
if (pid > 0) { // parent process
int i = 0;
for (i = 0; i < 5; i++) {
usleep(100);
printf("this is parent process i=%d\n", i);
}
}
while(1);
return 0;
}
在ubutun下面编译:gcc my_fork.c -o my_fork
,编译完之后运行,可以看到两个进程都开始运行
- 验证属于不同进程间的同名变量,不能互相访问
关注下面的变量 process_inter
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>
#include "sys/types.h"
int main()
{
pid_t pid;
int process_inter = 0;
pid = fork();
if (pid == 0) { // child process
int i = 0;
while (process_inter == 0);
for (i = 0; i < 5; i++) {
usleep(100);
printf("this is child process i=%d\n", i);
}
}
if (pid > 0) { // parent process
int i = 0;
for (i = 0; i < 5; i++) {
usleep(100);
printf("this is parent process i=%d\n", i);
}
process_inter == 1;
}
while(1);
return 0;
}
编译后运行,发现父进程在运行,但是子进程一直没有运行,说明在子进程中process_inter的值一直是0,但是我们在父进程中已经修改了这个值为1,所以可以验证,同名变量在不同进程之间是两个完全不同的变量,它们之间不存在任何联系
- 验证管道读阻塞
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include <unistd.h>
int main()
{
int fd[2];
int ret = 0;
char write_buf[] = "Hello linux";
char read_buf[128] = {0};
ret = pipe(fd);
if (ret < 0) {
printf("create pipe fail\n");
return -1;
}
printf("create pipe sucess fd[0]=%d fd[1]=%d\n", fd[0], fd[1]);
write(fd[1], write_buf, sizeof(write_buf));
read(fd[0], read_buf, sizeof(read_buf));
printf("1st read_buf=%s\n", read_buf);
// read 2nd time from pipe, it will block
memset(read_buf, 0, sizeof(read_buf));
read(fd[0], read_buf, sizeof(read_buf));
printf("2nd read_buf=%s\n", read_buf);
close(fd[0]);
close(fd[1]);
return 0;
}
编译后运行,发现只有打印1st read_buf=
,而没有打印2nd read_buf
,显然读完之后,管道中的内容就不存在了,此时再来读取就会阻塞住。
- 验证管道可以写入的最大长度
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include <unistd.h>
int main()
{
int fd[2], i = 0;
int ret = 0;
char write_buf[] = "Hello linux";
char read_buf[128] = {0};
char a[1] = {1};
ret = pipe(fd);
if (ret < 0) {
printf("create pipe fail\n");
return -1;
}
printf("create pipe sucess fd[0]=%d fd[1]=%d\n", fd[0], fd[1]);
for (i = 0; i < 65536; i++) {
write(fd[1], a, sizeof(a));
}
printf("write end\n");
//read(fd[0], read_buf, sizeof(read_buf));
//printf("1st read_buf=%s\n", read_buf);
close(fd[0]);
close(fd[1]);
return 0;
}
每次写入一个字节,重复写入N次,一直到写入失败阻塞住,可以发现能够写入的最大值是65536
- 验证父子通信
关注变量process_inter,在父进程中将这个值为1写入到管道中,在子进程中读取管道中的这个值,发现能够读取到这个值为1.需要注意的是这样的通信方式只能在父子进程(亲缘关系)中实现,在两个无关的进程间不能实现,因为fork函数将父进程蹭的所有内容进行了拷贝,包括 fd 文件描述符,所以能实现父子进程通信
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>
#include "sys/types.h"
int main()
{
pid_t pid;
char process_inter = 0;
int fd[2], ret = 0;
ret = pipe(fd);
if (ret < 0) {
printf("create pipe fail\n");
return -1;
}
printf("create pipe sucess\n");
pid = fork();
if (pid == 0) { // child process
int i = 0;
read(fd[0], &process_inter, sizeof(process_inter)); // if pipe empty ---> sleep
while (process_inter == 0);
for (i = 0; i < 5; i++) {
usleep(100);
printf("this is child process i=%d\n", i);
}
}
if (pid > 0) { // parent process
int i = 0;
for (i = 0; i < 5; i++) {
usleep(100);
printf("this is parent process i=%d\n", i);
}
process_inter = 1;
sleep(5);
write(fd[1], &process_inter, sizeof(process_inter));
}
while(1);
return 0;
}