一、

read

一、管道的实现

//源代码

#include<stdio.h>
#include<unistd.h>
#include <sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    //1、创建管道
    int pipefd[2]={0};
    int n=pipe(pipefd);
    if(n<0)
    {
        perror("pipe");
        return 1;

    }

    printf("pipefd[0]:%d,pipefd[1]:%d\n",pipefd[0],pipefd[1]);
    //2、fork创建子进程
    pid_t id=fork();
    if(id==0)
    {
        //child   w
     
        close(pipefd[0]);
        char *msg="hello bit";   
        // write(pipefd[1],msg,strlen(msg));
        int cnt=10;
        char outbuffer[1024];
        
        while(cnt)
        {
            snprintf(outbuffer,sizeof(outbuffer),"f->c# %s %d %d\n",msg,cnt--,getpid());
            write(pipefd[1],outbuffer,strlen(outbuffer));
            sleep(1);
        }
        exit(0);
    }

    //父进程   r
    close(pipefd[1]);
    char inbuffer[1024];

    while(1)
    {
       ssize_t n= read(pipefd[0],inbuffer,sizeof((inbuffer)-1));
       if (n>0)
       {
        inbuffer[n]=0;
        printf("%s",inbuffer);
       }
    }
    pid_t rid=waitpid(id,NULL,0);
    (void)rid;//防止编译有警告








    return 0;




}

//Makefile
code:code.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f code

运行结果:

二、匿名管道的特性(5种)

1、管道只能单向通信,单工通信

2、匿名管道只能用来进行父子通信(继承内核资源),具有血缘关系的进程之间。

3、管道是面向字节流的

4、管道的生命周期是随进程的。

5、管道通信,对于多进程而言,是自带互斥同步机制。

当进程退出时,PCB被释放,文件描述符表也会被释放,进程持有的文件描述符也会被关闭,内核会将对应的struct file 的引用计数减1,当引用计数减到0时,struct file会被释放,此时确实没有进程再关联这个打开的文件对象。



三、管道读写的4种情况

:1、子进程写的慢,父进程就要阻塞等,等管道有数据,父进程才能读;管道为空,读就要阻塞,给写 机会。

互斥与同步

(管道通信,前提是让不同的进程。看到同一份资源--->文件-->文件的内核缓冲区--->内存块。)

属于父子进程的共享资源,并发访问导致的问题--->需要通过互斥与同步机制来保证数据一致性

互斥-->任何时刻只允许一个人访问资源,同步--->访问数据具有一定的顺序性。

2、子进程写的快,父进程不读,管道一旦被写满,子进程就必须阻塞了。写满就必须要让父进程读了。---》管道满了,写就要阻塞,给读机会。

3、 读端在读,写端关闭,读端读完管道中剩余数据,再读,就会读取“ ”(空串),read返回值为0,表明读管道,读到文件结尾。

4、 写端一直在写,读端不读关闭fd。(OS会直接杀掉写的进程)

内核会向写进程发送 SIGPIPE 信号,默认终止进程;若捕获或忽略该信号,write 会返回 -1,并设置 errnoEPIPE。告知写进程 “无人消费数据”,避免无效写入。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐