PIPE

pipe-image.png

書式

#include <unisdt.h>

int pipe(int fildes[2]);

#include <fcntl.h>
int pipe2(int fildes[2], int flags);

pipeはファイルディスクリプタ(fd)のペアを作成する。引数には、ペアのfdを格納するint型の配列を指定する。0番目がend-of-read、1番目がwrite-endとなる。pipe関数でパイプを作成した後、forkでプロセスを生成すると、親子で共通のパイプを参照した状態となる。その後、例えば親側で0番をclose、子側で1番をcloseすれば、親から子への単方向のデータフローを実現することができる。

pipe2は、flagsを渡してファイルディスクリプタに関する属性を設定することができる。flagsが0の場合、pipeと同様となる。flagsに指定できる属性は以下である。

関連

int filedes[2];

// pipe
pipe(filedes);
fcntl(fildes[0], F_SETFL, O_NONBLOCK);
fcntl(fildes[1], F_SETFL, O_NONBLOCK);
fcntl(fildes[0], F_SETFD, FD_CLOEXEC);
fcntl(fildes[1], F_SETFD, FD_CLOEXEC);

// pipe2
pipe2(filedes, O_CLOEXEC | O_NONBLOCK);

read-endがcloseしている状態でwriteするとエラーで-1が返る(SIGPIPE)。write-endがcloseしている状態でreadすると、0(EOF)となる。

なお、パイプバッファのサイズは制限があり、パイプがfullの状態でwriteするとblockまたは失敗する。システムの実装によって異なるため注意。2.6.35以降では、サイズは16ページとなっている。また、fcntlで変更可能となっている。

参考 PIPE(7) - on http://man7.org/linux/man-pages/man7/pipe.7.html

返り値

成功時は0を返す。失敗時は-1を返し、errnoに以下の値がセットされる。

エラー

pipe2()

親プロセスと子プロセスでpipeを経由して通信

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <sys/types.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6.  
  7. /*
  8.  * Pipe
  9.  */
  10. static int pipe_fds[2] = {-1, -1}; /* read-end, write-end */
  11.  
  12.  
  13. int main(int argc, char *argv[])
  14. {
  15. pid_t pid;
  16. int status;
  17. ssize_t ret;
  18. char buf[16];
  19. char *message = "hello";
  20.  
  21. if (pipe(pipe_fds) < 0)
  22. {
  23. perror("failed to create pipe");
  24. exit(1);
  25. }
  26.  
  27. pid = fork();
  28.  
  29. if (pid < 0)
  30. {
  31. perror("failed to do fork");
  32. exit(1);
  33. }
  34. else if (pid == 0)
  35. {
  36. close(pipe_fds[1]);
  37. sleep(1);
  38. ret = read(pipe_fds[0], buf, sizeof(buf));
  39. if (ret < 0)
  40. {
  41. perror("faild to read");
  42. exit(1);
  43. }
  44. buf[sizeof(buf) - 1] = '\0';
  45. printf("child read: %s\n", buf);
  46. exit(0);
  47. }
  48.  
  49. close(pipe_fds[0]);
  50.  
  51. printf("parent write: %s\n", message);
  52. ret = write(pipe_fds[1], message, strlen(message));
  53. if (ret < 0)
  54. {
  55. perror("faild to write");
  56. }
  57.  
  58. waitpid(pid, &status, 0);
  59. exit(0);
  60. }
  61.  
  62.  
  63. /*
  64. 出力例:
  65. parent write: hello
  66. child read: hello
  67. */

実験 pipeごとのバッファ、パイプサイズの確認

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <fcntl.h>
  4. #include <errno.h>
  5. #include <stdlib.h>
  6. #include <limits.h>
  7. #include <string.h>
  8.  
  9. #define CHILD_NUM 5
  10.  
  11. #define PIPE_BUFFER 65537
  12.  
  13. /*
  14.  * Pipe
  15.  */
  16. int pipe_fds[CHILD_NUM][2];
  17. int mypid;
  18.  
  19. pid_t child_procs[CHILD_NUM];
  20.  
  21. static pid_t spawn(int id);
  22. static void do_it(void);
  23.  
  24. static pid_t spawn(int id)
  25. {
  26. pid_t pid;
  27.  
  28. pid = fork();
  29.  
  30. if (pid < 0) {
  31. perror("failed to fork");
  32. exit(1);
  33. } else if (pid == 0) {
  34. close(pipe_fds[id][1]);
  35. sleep(1);
  36. do_it();
  37. }
  38.  
  39. return pid;
  40. }
  41.  
  42. static void do_it(void)
  43. {
  44. while (1)
  45. {
  46. if (getppid() != mypid)
  47. break;
  48.   sleep(5);
  49. }
  50. exit(0);
  51. }
  52.  
  53.  
  54. int main(int argc, char *argv[])
  55. {
  56. int i, j;
  57. ssize_t ret;
  58.  
  59. mypid = getpid();
  60.  
  61. for (i = 0; i < CHILD_NUM; ++i)
  62. {
  63. if (pipe(pipe_fds[i]) < 0)
  64. {
  65. perror("faild to create a pipe");
  66. exit(1);
  67. }
  68.  
  69. /*
  70. * Set fd to non-blocking mode.
  71. */
  72. if (fcntl(pipe_fds[i][0], F_SETFL, O_NONBLOCK) == -1)
  73. {
  74. perror("faild to fcntl");
  75. exit(1);
  76. }
  77.  
  78. if (fcntl(pipe_fds[i][1], F_SETFL, O_NONBLOCK) == -1)
  79. {
  80. perror("faild to fcntl");
  81. exit(1);
  82. }
  83.  
  84. child_procs[i] = spawn(i);
  85. }
  86.  
  87. for (i = 0; i < CHILD_NUM; ++i)
  88. {
  89. for (j = 1; j <= PIPE_BUFFER; j++)
  90. {
  91. ret = write(pipe_fds[i][1], "a", 1);
  92.  
  93. if (j >= PIPE_BUFFER - 1)
  94. {
  95. printf("Proc no.%d: writing %d byte ... ", i, j);
  96.  
  97. if (ret < 0)
  98. {
  99. fprintf(stderr, "error : %s\n", strerror(errno));
  100. break;
  101. }
  102. else
  103. printf("ok\n");
  104. }
  105. }
  106. }
  107.  
  108. exit(0);
  109. }
  110.  
  111.  
  112. /*
  113. 出力例: maxOS High Seirra 10.13.3
  114. Proc no.0: writing 65536 byte ... ok
  115. Proc no.0: writing 65537 byte ... error : Resource temporarily unavailable
  116. Proc no.1: writing 65536 byte ... ok
  117. Proc no.1: writing 65537 byte ... error : Resource temporarily unavailable
  118. Proc no.2: writing 65536 byte ... ok
  119. Proc no.2: writing 65537 byte ... error : Resource temporarily unavailable
  120. Proc no.3: writing 65536 byte ... ok
  121. Proc no.3: writing 65537 byte ... error : Resource temporarily unavailable
  122. Proc no.4: writing 65536 byte ... ok
  123. Proc no.4: writing 65537 byte ... error : Resource temporarily unavailable
  124. */

PostgreSQLのpostmasterダウン検知

PostgreSQLでは、postmasterプロセスのダウン検知をpipeを使って実装している。子プロセスは、親プロセスのディスクリプタをチェックし、親プロセスの生死を確認している。以下はイメージソースである(大体イメージソースのようなことをしている)。

参考PostmasterIsAlive() - https://git.postgresql.org/gitweb/

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <fcntl.h>
  4. #include <errno.h>
  5. #include <stdlib.h>
  6.  
  7.  
  8. #define CHILD_NUM 3
  9.  
  10. /*
  11.  * Pipe
  12.  */
  13. int postmaster_alive_fds[2] = {-1, -1};
  14.  
  15. pid_t child_procs[CHILD_NUM];
  16.  
  17. static pid_t spawn(void);
  18. static void do_it(void);
  19.  
  20. static pid_t spawn(void)
  21. {
  22. pid_t pid;
  23.  
  24. pid = fork();
  25.  
  26. if (pid < 0) {
  27. perror("failed to fork");
  28. exit(1);
  29. } else if (pid == 0) {
  30. close(postmaster_alive_fds[1]);
  31. do_it();
  32. }
  33.  
  34. return pid;
  35. }
  36.  
  37. static void do_it(void)
  38. {
  39. ssize_t ret;
  40. char c;
  41.  
  42. while (1)
  43. {
  44. ret = read(postmaster_alive_fds[0], &c, 1);
  45. if (ret < 0)
  46. {
  47. if (errno == EAGAIN || errno == EWOULDBLOCK)
  48. goto RETRY; /* postmaster is alive */
  49. else
  50. {
  51. perror("failed to read");
  52. break;
  53. }
  54. }
  55. else if (ret > 0)
  56. {
  57. printf("read invalid data %c\n", c);
  58. break;
  59. }
  60. else
  61. break; /* postmaster may be dead */
  62. RETRY:
  63. sleep(5);
  64. }
  65.  
  66. exit(0);
  67. }
  68.  
  69.  
  70. int main(int argc, char *argv[])
  71. {
  72. int i;
  73.  
  74. if (pipe(postmaster_alive_fds) < 0)
  75. {
  76. perror("faild to create a pipe");
  77. exit(1);
  78. }
  79.  
  80. /*
  81. * Set fd to non-blocking mode.
  82. */
  83. if (fcntl(postmaster_alive_fds[0], F_SETFL, O_NONBLOCK) == -1)
  84. {
  85. perror("faild to fcntl");
  86. exit(1);
  87. }
  88.  
  89. for (i = 0; i < CHILD_NUM; ++i)
  90. {
  91. child_procs[i] = spawn();
  92. }
  93.  
  94. close(postmaster_alive_fds[0]);
  95.  
  96. sleep(3);
  97. printf("postmaster process down\n");
  98.  
  99. exit(0);
  100. }

共通の親を持つ子プロセス間同士で通信

proc1をread、proc2をwriteとしている。

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <unistd.h>
  4. #include <errno.h>
  5. #include <stdlib.h>
  6.  
  7.  
  8. #define READ_END 0
  9. #define WRITE_END 1
  10.  
  11. /*
  12.  * Pipe
  13.  */
  14. int pipe_fds[2] = {-1, -1};
  15.  
  16.  
  17. int main(int argc, char *argv[])
  18. {
  19. int status;
  20. pid_t proc1;
  21. pid_t proc2;
  22. pid_t pid;
  23.  
  24. if (pipe(pipe_fds) < 0)
  25. {
  26. perror("faild to create a pipe");
  27. exit(1);
  28. }
  29.  
  30. /*
  31. * Proc1
  32. */
  33. proc1 = fork();
  34.  
  35. if (proc1 < 0)
  36. {
  37. perror("failed to do fork");
  38. exit(1);
  39. }
  40. else if (proc1 == 0)
  41. {
  42. char buf[32] = {'\0'};
  43. size_t ret;
  44.  
  45. close(pipe_fds[WRITE_END]);
  46. ret = read(pipe_fds[READ_END], buf, sizeof(buf));
  47. if (ret == 0)
  48. {
  49. perror("proc1: failed to read from pipe");
  50. exit(1);
  51. }
  52.  
  53. printf("proc1 read: %s\n", buf);
  54. exit(0);
  55. }
  56.  
  57. /*
  58. * Proc2
  59. */
  60. proc2 = fork();
  61.  
  62. if (proc2 < 0)
  63. {
  64. perror("failed to do fork");
  65. exit(1);
  66. }
  67. else if (proc2 == 0)
  68. {
  69. close(pipe_fds[READ_END]);
  70. char *message = "hello";
  71. write(pipe_fds[WRITE_END], message, strlen(message) + 1);
  72. exit(0);
  73. }
  74.  
  75. close(pipe_fds[READ_END]);
  76. close(pipe_fds[WRITE_END]);
  77.  
  78. do {
  79. pid = waitpid(-1, &status, 0);
  80. } while (pid > 0 || errno == EINTR);
  81.  
  82. puts("done");
  83. exit(0);
  84. }

参考リンク


添付ファイル: filepipe-image.png 195件 [詳細]

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
目次
ダブルクリックで閉じるTOP | 閉じる
GO TO TOP