Linux进程间通信-管道

来源:互联网 发布:韩信厉害知乎 编辑:程序博客网 时间:2024/05/20 12:25

转载自:http://blog.csdn.net/a1009563517/article/details/46841129
管道是进程间通信方式之一,进程间可以利用管道来进行通信,好比两个地方,相隔了一条河,管道就是这条河上的一座桥,两个地方通过这座桥才得以进行相互访问。
优点:1.管道可以使两个需要相互交互的进程调用管道来实现相互数据的交互
2.多个进程同时向同一个管道写数据时,当数据小于PIPE_BUF(4096),那么写操作是原子操作,不必给这多个进程的写操作加锁
缺点:1.管道只能用于具有亲缘关系的进程
2.管道是半双工的,虽然现在有全双工的,但是考虑到可移植性,不能假设所有系统都支持全双工的,所以使用管道时最好用半双工
在Linux里管道类似于文件,引用管道类似于向文件的读写操作,管道操作如下:
1.首先调用pipe建立一个管道
2.读进程把pipe返回的管道标识写关闭,写进程把管道标识的读关闭,调用close来关闭
3.写进程往管道写数据,读进程从管道中读数据
注意:1.如果读段和写段都打开,写段还没写数据,读段会阻塞
2.写端写满管道时写端下次写会阻塞
3.只有当管道中有PIPE_BUF的空间未写时,写段才会往里面写数据,否则一直阻塞直到管道中的可写空间>PIPE_BUF
4.读段从管道读取数据直到管道中没有数据,则阻塞直到写端再次向管道写入数据
5.多个读端,如果读的大小小于pipe_buf则读是原子的,读取出来的数据顺序与写时一致,如果读的大小大于 pipe_buf则读不是原子的,读取出来的数据顺序是错乱的
6.写端向管道写数据时,如果写入的数据大小小于pipe_buf则是原子写入得,顺序保持与写入的一致,如果大小>pipe_bu则是非原子写入,管道里的数据是错乱的
7.写端关闭停止写入数据时读端会一直读直到把所有数据读出阻塞
PIPE_BUF
对管道写时,大小应该小于PIPE_BUF(可用fpathconf获取),则是原子操作,则写入的数据是顺序的,如果写操作大小超过PIPE_BUF则是非原子,所写的数据会错乱。linux的PIPE_BUF是4096。
阻塞
写的数据小于PIPE_BUF所有的数据会被原子的写入,如果没有空间,则会阻塞
写的数据大于PIPE_BUF,写操作是非原子的,写的数据会错乱,写完数据后会阻塞
非阻塞
写的数据小于PIPE_BUF如果有剩余的空间则数据会立即写入管道,否则出错
写的数据大于PIPE_BUF,如果管道满了,则失败,否则则会写入数据,写入的数据大小视空余空间,有可能其他进程写操作造成错乱
管道的删除
直至最后一个访问管道的进程结束,管道也会被完全的删除
PIPE_BUF
指原子写操作的大小
PIPE_SIZE
指管道大小

代码如下:

int main()  {      /*管道*/      int     b_fd[2];      int     b_ret;      int     b_num, b_max;      pid_t   b_pid[10];      b_ret = pipe(b_fd);      if(b_ret < 0)      {          printf("pipe fail line = %d, fun = %s, file = %s\n", __LINE__, __func__, __FILE__);          return 0;      }      b_num = 0;      printf("read max = %d, write max = %d, %d, %d, %d\n", fpathconf(b_fd[0], _PC_PIPE_BUF), \          fpathconf(b_fd[1], _PC_PIPE_BUF), b_fd[0], b_fd[1], STDOUT_FILENO);      b_pid[b_num] = fork();      if(b_pid[b_num] < 0)      {          printf("fork fail line = %d, fun = %s, file = %s\n", __LINE__, __func__, __FILE__);          return 0;      }      else if(0 == b_pid[b_num])      {          /*子进程*/          ipc_pipe_fun1(b_fd);      }      b_num++;      b_pid[b_num] = fork();      if(b_pid[b_num] < 0)      {          printf("fork fail line = %d, fun = %s, file = %s\n", __LINE__, __func__, __FILE__);          return 0;      }      else if(0 == b_pid[b_num])      {          /*子进程*/          ipc_pipe_fun2(b_fd);      }      b_num++;      b_pid[b_num] = fork();      if(b_pid[b_num] < 0)      {          printf("fork fail line = %d, fun = %s, file = %s\n", __LINE__, __func__, __FILE__);          return 0;      }      else if(0 == b_pid[b_num])      {          /*子进程*/          ipc_pipe_fun1(b_fd);      }      b_num++;      while(1)      {          sleep(1000);      }      return 0;  }  int ipc_pipe_fun1(int * a_fd)  {      int     b_ret, b_ttl = 0;      char    b_buf[4098];      close(a_fd[1]);      while(1)      {          memset(b_buf, 0, sizeof(b_buf));          b_ret = read(a_fd[0], b_buf, 100);          b_ttl += b_ret;          printf("==id = %d===read data len = %d \n", getpid(), b_ret);          printf("==id = %d====b_ttl = %d==read b_buf = %s \n", getpid(), b_ttl, b_buf);          sleep(1);      }      return 0;  }  int ipc_pipe_fun2(int * a_fd)  {      int     b_ret;      char    b_buf[100];      int     b_num = 0, b_len = 0, b_ttl = 0;      char  * b_mall = (char *)malloc(65535);      close(a_fd[0]);      while(1)      {          memset(b_buf, 0, sizeof(b_buf));          b_len = sprintf(b_buf, "%d|", b_num);          b_num = b_num%100000;          b_ret = write(a_fd[1], b_buf, b_len);          b_ttl += b_ret;          printf("write data len = %d, b_ttl = %d\n", b_ret, b_ttl);          printf("write b_buf = %s\n", b_buf);          b_num++;      }      return 0;  }  <span style="font-family:Simsun;font-size:18px;">  </span>  
0 0