进程间通信
Posted yangguang-it
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进程间通信相关的知识,希望对你有一定的参考价值。
1.管道
对于具有公共祖先的进程,其管道是建立在3-4G的内核空间中的。每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
调用pipe函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端一个写端,然后通过filedes参数传出给用户程序两个文件描述符,filedes[0]指向管道的读端,filedes[1]指向管道的写端(很好记,就像0是标准输入1是标准输出一样)。所以管道在用户程序看起来就像一个打开的文件,通过read(filedes[0]);或者write(filedes[1]);向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0,调用失败返回-1。
#include <sys/wait.h> #include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<stdlib.h> #include<string.h> int main(void) { pid_t pid; int fd[2]; if(pipe(fd)<0) { perror("pipe"); exit(1); } printf("fd[0]=%d, fd[1]= %d\\n",fd[0],fd[1]); if((pid=fork())<0) { perror("fork"); exit(1); } else if(pid==0)//child { char c_str[1024]; int n; close(fd[1]);//关闭写端口 n=read(fd[0],c_str,sizeof(c_str)/sizeof(c_str[0]));//由于不知道读多少,所以读取最大长度 close(fd[0]); write(STDOUT_FILENO,c_str,n); } else//parents { char str[]="hello pipe!\\n"; sleep(2); close(fd[0]);//关闭读端口 write(fd[1],str,strlen(str)); close(fd[1]); wait(NULL);//等待回收子进程资源 } return 0; }
在父进程没有传输数据在管道中时,子进程中的read函数会阻塞等待。我们可以使用fcntl函数改变一个已经打开文件的属性,如重新设置读、写、追加、非阻塞等标志。
#include<stdio.h> #include<sys/types.h> #include<sys/wait.h> #include<unistd.h> #include<stdlib.h> #include<string.h> #include<fcntl.h> #include<errno.h> int main(void) { pid_t pid; int fd[2]; if(pipe(fd)<0) { perror("pipe"); exit(1); } printf("fd[0]=%d, fd[1]= %d\\n",fd[0],fd[1]); if((pid=fork())<0) { perror("fork"); exit(1); } else if(pid==0)//child { char c_str[1024]; int n,flags; flags=fcntl(fd[0],F_GETFL); flags |=O_NONBLOCK; if(fcntl(fd[0],F_SETFL,flags)==-1) { perror("fcntl"); exit(1); } close(fd[1]);//关闭写端口 tryagain: n=read(fd[0],c_str,sizeof(c_str)/sizeof(c_str[0]));//由于不知道读多少,所以读取最大长度 if(n<0) { if(errno==EAGAIN) { write(STDOUT_FILENO,"try again...\\n",13); sleep(1); goto tryagain; } perror("read"); exit(1); } close(fd[0]); write(STDOUT_FILENO,c_str,n); } else//parents { char str[]="hello pipe!\\n"; sleep(2); close(fd[0]);//关闭读端口 write(fd[1],str,strlen(str)); close(fd[1]); wait(NULL);//等待回收子进程资源 } return 0; }
此时,read已经不再是阻塞了。需要注意的是,使用管道技术,应该在fork之前创建管道。
2.FIFO
以上是关于进程间通信的主要内容,如果未能解决你的问题,请参考以下文章