进程间通信-管道

清疚 2022-08-02 05:52 363阅读 0赞
  1. 管道是进程间通信方式之一,进程间可以利用管道来进行通信,好比两个地方,相隔了一条河,管道就是这条河上的一座桥,两个地方通过这座桥才得以进行相互访问。

优点:1.管道可以使两个需要相互交互的进程调用管道来实现相互数据的交互

  1. 2.多个进程同时向同一个管道写数据时,当数据小于PIPE\_BUF4096),那么写操作是原子操作,不必给这多个进程的写操作加锁

缺点:1.管道只能用于具有亲缘关系的进程

  1. 2.管道是半双工的,虽然现在有全双工的,但是考虑到可移植性,不能假设所有系统都支持全双工的,所以使用管道时最好用半双工
  2. linux里管道类似于文件,引用管道类似于向文件的读写操作,管道操作如下:
  3. 1.首先调用pipe建立一个管道
  4. 2.读进程把pipe返回的管道标识写关闭,写进程把管道标识的读关闭,调用close来关闭
  5. 3.写进程往管道写数据,读进程从管道中读数据

注意:1.如果读段和写段都打开,写段还没写数据,读段会阻塞
2.写端写满管道时写端下次写会阻塞
3.只有当管道中有PIPE_BUF的空间未写时,写段才会往里面写数据,否则一直阻塞直到管道中的可写空间>PIPE_BUF
4.读段从管道读取数据直到管道中没有数据,则阻塞直到写端再次向管道写入数据
5.多个读端,如果读的大小小于pipe_buf则读是原子的,读取出来的数据顺序与写时一致,如果读的大小大于 pipe_buf则读不是原子的,读取出来的数据顺序是错乱的
6.写端向管道写数据时,如果写入的数据大小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

指管道大小

代码如下:

  1. int main()
  2. {
  3. /*管道*/
  4. int b_fd[2];
  5. int b_ret;
  6. int b_num, b_max;
  7. pid_t b_pid[10];
  8. b_ret = pipe(b_fd);
  9. if(b_ret < 0)
  10. {
  11. printf("pipe fail line = %d, fun = %s, file = %s\n", __LINE__, __func__, __FILE__);
  12. return 0;
  13. }
  14. b_num = 0;
  15. printf("read max = %d, write max = %d, %d, %d, %d\n", fpathconf(b_fd[0], _PC_PIPE_BUF), \
  16. fpathconf(b_fd[1], _PC_PIPE_BUF), b_fd[0], b_fd[1], STDOUT_FILENO);
  17. b_pid[b_num] = fork();
  18. if(b_pid[b_num] < 0)
  19. {
  20. printf("fork fail line = %d, fun = %s, file = %s\n", __LINE__, __func__, __FILE__);
  21. return 0;
  22. }
  23. else if(0 == b_pid[b_num])
  24. {
  25. /*子进程*/
  26. ipc_pipe_fun1(b_fd);
  27. }
  28. b_num++;
  29. b_pid[b_num] = fork();
  30. if(b_pid[b_num] < 0)
  31. {
  32. printf("fork fail line = %d, fun = %s, file = %s\n", __LINE__, __func__, __FILE__);
  33. return 0;
  34. }
  35. else if(0 == b_pid[b_num])
  36. {
  37. /*子进程*/
  38. ipc_pipe_fun2(b_fd);
  39. }
  40. b_num++;
  41. b_pid[b_num] = fork();
  42. if(b_pid[b_num] < 0)
  43. {
  44. printf("fork fail line = %d, fun = %s, file = %s\n", __LINE__, __func__, __FILE__);
  45. return 0;
  46. }
  47. else if(0 == b_pid[b_num])
  48. {
  49. /*子进程*/
  50. ipc_pipe_fun1(b_fd);
  51. }
  52. b_num++;
  53. while(1)
  54. {
  55. sleep(1000);
  56. }
  57. return 0;
  58. }
  59. int ipc_pipe_fun1(int * a_fd)
  60. {
  61. int b_ret, b_ttl = 0;
  62. char b_buf[4098];
  63. close(a_fd[1]);
  64. while(1)
  65. {
  66. memset(b_buf, 0, sizeof(b_buf));
  67. b_ret = read(a_fd[0], b_buf, 100);
  68. b_ttl += b_ret;
  69. printf("==id = %d===read data len = %d \n", getpid(), b_ret);
  70. printf("==id = %d====b_ttl = %d==read b_buf = %s \n", getpid(), b_ttl, b_buf);
  71. sleep(1);
  72. }
  73. return 0;
  74. }
  75. int ipc_pipe_fun2(int * a_fd)
  76. {
  77. int b_ret;
  78. char b_buf[100];
  79. int b_num = 0, b_len = 0, b_ttl = 0;
  80. char * b_mall = (char *)malloc(65535);
  81. close(a_fd[0]);
  82. while(1)
  83. {
  84. memset(b_buf, 0, sizeof(b_buf));
  85. b_len = sprintf(b_buf, "%d|", b_num);
  86. b_num = b_num%100000;
  87. b_ret = write(a_fd[1], b_buf, b_len);
  88. b_ttl += b_ret;
  89. printf("write data len = %d, b_ttl = %d\n", b_ret, b_ttl);
  90. printf("write b_buf = %s\n", b_buf);
  91. b_num++;
  92. }
  93. return 0;
  94. }
  95. <span style="font-family:Simsun;font-size:18px;">
  96. </span>

发表评论

表情:
评论列表 (有 0 条评论,363人围观)

还没有评论,来说两句吧...

相关阅读

    相关 进程通信-管道

          管道是进程间通信方式之一,进程间可以利用管道来进行通信,好比两个地方,相隔了一条河,管道就是这条河上的一座桥,两个地方通过这座桥才得以进行相互访问。 优点:1.管

    相关 进程通信---管道

    进程间通信 一般而言,不同的进程看到的那一份公共资源,是由操作系统提供的,任何一个进程的全局变量在另一个进程中都看不到,所以,进程之间要交换数据就需要通过内核,在内核中开

    相关 管道实现进程通信

    一、无名管道 1、什么是管道? 管道用于相关进程间的通信,相当于一个传递工具; 1、特点 (1)无名管道是半双工的,在管道的一端只能进行读或者是写,二者不可同