如何使用pipe()系统调用?用法示例

2021年3月29日17:16:34 发表评论 1,357 次浏览

先决条件:I/O系统调用

从概念上讲, 管道是两个进程之间的连接, 以使一个进程的标准输出成为另一进程的标准输入。在UNIX操作系统中, 管道对于相关进程之间的通信(进程间通信)很有用。

管道仅是单向通信, 即我们可以使用管道, 以便一个进程向管道写入数据, 而另一个进程从管道读取数据。它打开一个管道, 该管道是主存储器中被视为"虚拟文件"的区域。

创建过程及其所有子过程均可使用该管道进行读取和写入。一个进程可以写入此"虚拟文件"或管道, 而另一个相关进程可以从中读取。

如果某个进程在将某些内容写入管道之前尝试读取, 则该过程将被挂起, 直到写入某些内容为止。

管道系统调用在进程的打开文件表中找到前两个可用位置, 并将其分配给管道的读取和写入端。

如何使用pipe()系统调用?用法示例1

C语言语法:

int pipe(int fds[2]);

Parameters :
fd[0] will be the fd(file descriptor) for the 
read end of pipe.
fd[1] will be the fd for the write end of pipe.
Returns : 0 on Success.
-1 on error.

管道行为先进先出(先进先出), 管道的行为类似于队列数据结构。读写大小不必在这里匹配。我们可以写512一次只能读取1个字节, 但在管道中一次只能读取1个字节。

// C program to illustrate
// pipe system call in C
#include <stdio.h>
#include <unistd.h>
#define MSGSIZE 16
char * msg1 = "hello, world #1" ;
char * msg2 = "hello, world #2" ;
char * msg3 = "hello, world #3" ;
  
int main()
{
     char inbuf[MSGSIZE];
     int p[2], i;
  
     if (pipe(p) < 0)
         exit (1);
  
     /* continued */
     /* write pipe */
  
     write(p[1], msg1, MSGSIZE);
     write(p[1], msg2, MSGSIZE);
     write(p[1], msg3, MSGSIZE);
  
     for (i = 0; i < 3; i++) {
         /* read pipe */
         read(p[0], inbuf, MSGSIZE);
         printf ( "% s\n" , inbuf);
     }
     return 0;
}

输出如下:

hello, world #1
hello, world #2
hello, world #3

父进程和子进程共享管道

当我们使用叉子在任何进程中, 文件描述符在子进程和父进程之间均保持打开状态。如果我们在创建管道后调用fork, 则父级和子级可以通过管道进行通信。

如何使用pipe()系统调用?用法示例2

以下程序的输出。

// C program to illustrate
// pipe system call in C
// shared by Parent and Child
#include <stdio.h>
#include <unistd.h>
#define MSGSIZE 16
char * msg1 = "hello, world #1" ;
char * msg2 = "hello, world #2" ;
char * msg3 = "hello, world #3" ;
  
int main()
{
     char inbuf[MSGSIZE];
     int p[2], pid, nbytes;
  
     if (pipe(p) < 0)
         exit (1);
  
     /* continued */
     if ((pid = fork()) > 0) {
         write(p[1], msg1, MSGSIZE);
         write(p[1], msg2, MSGSIZE);
         write(p[1], msg3, MSGSIZE);
  
         // Adding this line will
         // not hang the program
         // close(p[1]);
         wait(NULL);
     }
  
     else {
         // Adding this line will
         // not hang the program
         // close(p[1]);
         while ((nbytes = read(p[0], inbuf, MSGSIZE)) > 0)
             printf ( "% s\n" , inbuf);
         if (nbytes != 0)
             exit (2);
         printf ( "Finished reading\n" );
     }
     return 0;
}

输出如下:

hello world, #1
hello world, #2
hello world, #3
(hangs)         //program does not terminate but hangs

在此代码中, 在完成读/写操作后, 父级和子级都阻塞而不是终止进程, 这就是程序挂起的原因。发生这种情况是因为读取系统调用获取的数据量与管道请求的数据量或管道的数据量(以较少者为准)相同。

  • 如果管道为空, 并且我们调用read系统调用, 则管道上的Reads将返回EOF(返回值0)如果没有进程打开写结束。
  • 如果有其他进程打开了用于写入的管道, 则读取将阻止新的数据, 因此此代码输出将挂起, 因为此处写入结束了父进程, 而子进程也没有关闭。

有关父进程和子进程共享管道的更多详细信息, 请参阅

演示fork()和pipe()的C程序.

如果发现任何不正确的地方, 或者想分享有关上述主题的更多信息, 请写评论。

木子山

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: