3

我试图理解命令pipe(2),例如:

int pipefd[2];
if (pipe(pipefd) == -1) {
    perror("pipe");
    exit(EXIT_FAILURE);
}

我想获得两个带有 , 的文件描述符shared memory,用于匿名管道(父子关系)。

例如,这是父子进程之间的简单对话:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <sys/wait.h>  
#include <unistd.h>    
#include <string.h>   
#define SHMSIZE 16
int main() {
   int shmid;
   char *shm;

   if(fork() == 0)   // child first

   {

      shmid = shmget(2009, SHMSIZE, 0);
      shm = shmat(shmid, 0, 0);
      char *s = (char *) shm;
      *s = '\0';
      int i;

      // child enters the input that would be stored in the shared memory
      for(i=0; i<3; i++) {
         int n;
         printf("Enter number<%i>: ", i);
         scanf("%d", &n);

         // convert the input into a c-string
         sprintf(s, "%s%d", s, n);
      }
      strcat(s, "\n");

      // display the contents of the shared memory
      printf ("I'm the child process , and I wrote:%s\n",shm);

      // detaches the shared memory segment
      shmdt(shm);
   }


   else   // parent

   {

       // get the segment
      shmid = shmget(2009, SHMSIZE, 0666 | IPC_CREAT);

      // attaching the segment to the father
      shm = shmat(shmid, 0, 0);

      // father waits for the son the finish
      wait(NULL);

      // father displays what the son wrote
      printf ("I'm the father , and my child wrote :%s\n",shm) ;

      // detaches the shared memory segment
      shmdt(shm);

      shmctl(shmid, IPC_RMID, NULL);
   }
   return 0;
}

输出非常简单:

Enter number<0>: 123
Enter number<1>: 567
Enter number<2>: 789
I'm the child process , and I wrote:123567789

I'm the father , and my child wrote :123567789

这是我的实现shm_pipe_pipe(),替换为pipe(2)

int shm_pipe_pipe(int spd[2])
{
    spd[0] = shmget(2009, SHMSIZE, 0);
    spd[1] = shmget(2009, SHMSIZE, 0666 | IPC_CREAT);

     if (spd[0] == -1 || spd[1] == -1)
         return -1;
     return 1;

}

我的问题是:

  1. 我知道那fd[0]是用来阅读和fd[1]写作的,但它们到底是什么?地址?

  2. 我上面写的功能shm_pipe_pipe似乎不起作用,它有什么问题?

谢谢`

4

1 回答 1

8
  1. 回答您的第一个问题,它们保存文件描述符。它们不是地址。它们是表的索引。该表实际上具有将由内核解释的地址(如果描述符是磁盘文件,则为文件系统,如果它是网络套接字,则为网络堆栈等)。文件的用户永远不会得到实际地址。只有包含实际地址的表的索引才会提供给用户。该表的结构非常复杂,并且在各个子系统中有所不同。但基本概念是相对相同的。

下图对磁盘文件有效。

此映像对磁盘文件有效

如果有两个独立的进程:

两个独立的进程

如果是管道..

Pipe就是这样工作的,它只有两个文件描述符

这是文件描述符表的一般视图 FDT

  1. pipefd您的第二个问题,您似乎正在尝试从返回的值填充文件描述符数组shmget()

man 2 shmget

shmget() 返回与参数键值关联的共享内存段的标识符。如果 key 的值为 IPC_PRIVATE 或 key 不是 IPC_PRIVATE,不存在与 key 对应的共享内存段,并且指定了 IPC_CREAT,则创建一个新的共享内存段,其大小等于 size 值向上舍入为 PAGE_SIZE 的倍数在 shmflg。

了解 shmget() 的作用很重要。它要求一个向上取整的大小(usnig 系统的PAGE_SIZE)。该内存段由密钥标识。所以内核维护了一个键值表。该表还包含共享内存区域的地址。现在,当您调用 时shmat(),您使用 查询此表,shmid并且返回的地址与您的进程地址空间相关联。

所以shmid返回的shmget()是系统维护的键值对表中的一个条目,与使用的文件描述符无关pipe()

底线是:

你不能这样实现pipe。为什么不看一下pipe自己的实际实现呢?

http://sourceware.org/git/?p=glibc.git;a=blob;f=io/pipe.c;h=07a37ae778046e56c13e62fd2a2fa678f5546424;hb=HEAD

尽管该文件中没有任何用处,因为它只是调用 other __pipe。您可以克隆一个 git 存储库并使用 cscope 来查找pipe.

于 2012-07-18T10:58:52.913 回答