admin 管理员组

文章数量: 888526

进程通信之管道通信

        进程通信,也成IPC机制,指的是实现两进程之间的通信(数据传递)。实现方法一个有五种:管道、信号量、共享内存、消息队列、套接字。最重要的是信号量、共享内存、消息队列。

1、管道

        管道在之前就有用到过,比如:ls | grep ”main“ 。"|" 就是管道,作用是将ls命令的结果写入管道文件,grep再从管道文件中读出数据,过滤出名字中有“main”的文件。

        这里只是管道的简单使用,如果要实现进程间的管道通信,就需要我们创建一个管道文件(p类型)。

        使用命令:mkfifo 。管道文件通常被称为FIFO

2、工作形式

        管道文件就如同生活中的管道一样,两端分别连接写端和读端,写端写入的数据经过管道被读端读取。并且,管道是半双工工作的,也就是只能一端读,一端写。

        读、写进程是同时运行的,任意一端进程未运行,则另一端被阻塞。若写端关闭,则读端读取到的数据数量为0,可以根据这一特点关闭读端;若读端关闭,则读端会向写端发生异常信号SIGPIPE,写端接收到信号后程序终止。

3、存在位置

        通常,文件都保存在磁盘中,待使用时调入内存访问,但是这样的访问形式就比较慢。通信最大的要求之一就是要快速。如果管道文件保存在磁盘中,两进程每通一句话,都要去磁盘访问一次管道文件,那就太慢了。所以管道文件是在创建好之后,在内存中保存的。这样虽然访问迅速,但也有一个问题:掉电丢失,但问题不大。

4、管道通信

        管道分为两类,一类是有名管道:用于任意两进程间通信;一类是无名管道:通常用于父子进程之间通信。

4.1、有名管道

        有名管道用于任意两进程间通信,并且只能一个进程读,一个进程写,所以先创建两个进程,一个写进程,一个读进程。

写进程a:

int main(){//写端只写;fdw为管道文件的文件描述符int fdw=open("FIFO",O_WRONLY);if(fdw==-1) exit(0);char buff[128];while(1){memset(buff,0,128);printf("Input:");//从键盘接收输入fgets(buff,128,stdin);//如果输入end,结束写入if(strncmp(buff,"end",3)==0){break;}//将写入的数据写入管道文件write(fdw,buff,strlen(buff));}close(fdw);exit(0);
}

读进程b:

int main(){//读端只读int fdr=open("FIFO",O_RDONLY);if(fdr==-1) exit(0);char buff[128];while(1){memset(buff,0,128);//num为从管道文件中读取到的数据数量;//若写端关闭,则num==0int num=read(fdr,buff,128);if(num==0){break;}printf("read:%s\n",buff);if(strncmp(buff,"end",3)==0){break;}}close(fdr);exit(0);
}

        当写端或读端单独运行时阻塞:

        在两终端同时运行读写进程,读写进程运行正常,且先a进程先写入数据,b进程读出数据。

        写入一次数据,读端读取一次数据。 

        写入“end”,通信结束。 

4.2、无名管道

        无名管道通常适用于父子进程通信,其创建需要使用pipe()函数。所需头文件:<unistd.h>

int pipe(int fds[2]); //创建成功返回0,失败返回-1;

        pipe()函数创建无名管道,并将读端和写端的描述符存放到fds数组返回。fds[0] 默认为读端描述符,fds[1] 默认为写端描述符。

        因为无名管道的创建是在进程复制时,让父子进程用于通信。但复制时由于发生了进程复制,父子进程就同时拥有读端与写端假设父进程是写端,子进程是读端,则让父进程关闭自己的读端入口,子进程关闭写端入口。

5、管道通信总结

        1、是半双工的。

        2、通信两进程需同时运行,否则运行的一端堵塞。

        3、管道中无数据时,读端阻塞。

        4、写端关闭,read返回0。

        5、读端关闭,会向写端发送异常信号,写端收到后异常终止。

本文标签: 进程通信之管道通信