全部博文(1493)
分类:
2012-08-21 08:50:01
原文地址:进程间的通信---管道 作者:Embedded_Li
管道分为有名管道和无名管道。
无名管道只能用于有亲系关系的进程间通信,即只能在父进程与子进程或兄弟进程间通信。有名管道可以用于任何进程间通信。管道有半双工,即在某一时刻只能有一个进程向管道里读或写。
管道是Unix系统IPC中最古老的的形式,管道有下面两种局限性:
1) 历史上它们是半双工的(即数据只能在一个方向上流动);
2) 它们只能在具有公共祖先的进程之间使用,一个管道由一个进程创建,然后该进程调用 用fork(),此后,父子进行之间就可应用该管道。
二、无名管道
调用fork后,要做什么取决于我们想要在的数据流的方向。对于从父进程到子进程的管道,父进程关闭管道的读端fd[0],子进程则关闭写端fd[1]。
1、 pipe函数
管道的创建。
#include int pipe(int filedes[2]); |
filedes:参数返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开,filedes[1]的输出是filedes[0]的输入;
shmflg:IPC_CREAT、IPC_EXCL、
2、 无名管道实例创建FIFO并fork,在父进程关闭读,子进程关闭写;实现半双工的管道通信。
#include
#include #include #include #include
int main(void) { int n, fd[2]; pid_t pid; char line[100];
if(pipe(fd)<0) printf("[%s:%d]: pipe error! \n",__FUNCTION__,__LINE__); if((pid = fork())<0) printf("[%s:%d]: fork error! \n",__FUNCTION__,__LINE__); else if(pid>0) //parant { close(fd[0]); write(fd[1],"hello word\n",12); }else { close(fd[1]); n = read(fd[0],line,sizeof(line)); printf("[%s:%d]: FIFO date = %s \n",__FUNCTION__,__LINE__,line); } exit (0); } |
运行结果为:
# gcc fifo.c -o lcl # ./lcl [main:26]: FIFO date = hello word |
三、有名管道
管道应用的一个重大限制是它没有名字因此,只能用于具有亲缘关系的进程间通信,有名管道(named pipe或FIFO)提出后,该限制得到了克服。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信。遵循先入先出,不支持lseek()定位。
1、 mkfifo函数创建FIFO管道。
#include #include int mkfifo(const char* pathname, mode_t mode); |
有名管道比无名管道多一个打开操作:open。FIFO的打开规则。
如果当前打开操作是为读而打开FIFO时,若已经有相应进程为写而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为写而打开该FIFO(当前打开设置了阻塞标志);或者成功返回。
3、 有名管道的读写规则从FIFO读数据:设置阻塞标志,当读取数据时,如果当前FIFO中有数据时,而其他进程正在进行读这些数据,或者无数据时,会阻塞当前进程。
读打开的阻塞标志,只对本进程的第一个读操作有作用,其实要执行的读操作将不再阻塞。
四、有名管道实例
#include #include #include #include #define FIFO "/home/lichenglong/study_key/FIFO"
int main() { char buffer[80]; int fd;
unlink(FIFO); mkfifo(FIFO,0666); if(fork()>0) { char s[] = "hello!\n"; fd = open(FIFO,O_WRONLY); write(fd,s,sizeof(s)); close(fd); }else { fd = open(FIFO,O_RDONLY); read(fd,buffer,80); printf("read data: %s",buffer); close(fd); } } |
运行结果
# gcc Gfifo.c # ./a.out read data: hello! |