linux进程间通信(二)---管道篇----无名管道

先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题
在这里插入图片描述
一 管道分类

类型特点
无名管道在文件系统中没有文件节点
有名管道在文件系统中有文件节点

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

二 无名管道示例代码

  1. 创建一个子进程
#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,编译完之后运行,可以看到两个进程都开始运行

  1. 验证属于不同进程间的同名变量,不能互相访问
    关注下面的变量 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,所以可以验证,同名变量在不同进程之间是两个完全不同的变量,它们之间不存在任何联系

  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,显然读完之后,管道中的内容就不存在了,此时再来读取就会阻塞住。

  1. 验证管道可以写入的最大长度
#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

  1. 验证父子通信
    关注变量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;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值