c - 在c中使用pipe()时,我的文件描述符神秘地设置为零

标签 c pipe file-descriptor

我是 Stack Overflow 的新手,在使用 C 中的管道时遇到问题。 该项目的目标是 fork 成两个子进程 B 和 C,它们写入管道。然后父进程从管道中读取数据,而无需等待 B 和 C 终止。 fork 必须使用 exec 系统调用来完成。 这是我的代码

int main()
{  

    printf("Starting process A, PID: %d\n",getpid());
    int fd[2];//file descriptors we're using in pipe
    int i;//used for while loops

    //start the pipe    
    pipe(fd);


    //Spawn process B
    int childB=fork();


    if (!childB)
    {
        //Now we're in process B
        printf("Forked b says fd[0] is %d and fd[1] is %d\n", fd[0], fd[1]);

        char *strArg[4];//string array for arguments

        //Set up the arguments we'll be using.
        strArg[0]= (char*) malloc(1000*sizeof(char));
        strArg[1]= (char*) malloc(1000*sizeof(char));
        strArg[2]= (char*) malloc(1000*sizeof(char));
        strArg[4]=NULL;


        printf("After initiliazing strings b says fd[0] is %d and fd[1] is %d\n", fd[0], fd[1]);
        sprintf(strArg[0], "%s", "PipeW1");
        int count=sprintf(strArg[1], "%d", fd[0]);
        count=sprintf(strArg[2], "%d", fd[1]);

        //We need to close the read end of the pipe before executing the writing code
        close(fd[0]);

        printf("About to execv B and fd[0] is %d and fd[1] is %d\n", fd[0], fd[1]);

        //Do the execv call to switch to the different process.
        int errcheck=execv("PipeW1", strArg);
        if (errcheck==-1)
        {
            printf("Error opening PipeW1.\n");
        }


    }   

//Still in process A. Going to start process C
int childC=fork();

if (!childC)
{
    printf("Forked c says fd[0] is %d and fd[1] is %d\n", fd[0], fd[1]);
    //We're in child C

    //Close the read end of pipe before doing any write code
    close(fd[0]);

    char *strArg[4];//string array for arguments

    //Set up the arguments we'll be using.
    strArg[0]= (char*) malloc(1000*sizeof(char));
    strArg[1]= (char*) malloc(1000*sizeof(char));
    strArg[2]= (char*) malloc(1000*sizeof(char));
    strArg[4]=NULL;

    //Put the name of the program into the appropriate argument
    sprintf(strArg[0], "%s", "PipeW2");
    int count=sprintf(strArg[1], "%d", fd[0]);
    count=sprintf(strArg[2], "%d", fd[1]);


    printf("About to execv C and fd[0] is %d and fd[1] is %d\n", fd[0], fd[1]);


    int errCheck=execv("PipeW2", strArg);
    if (errCheck==-1)
    {
        printf("Error execv C\n");
    }
    printf("I should have already made C..problem!\n");

}


close(fd[1]);//close output, we only read here





//If I wait for B and C to terminate, the program works without incident.
// int retCode;
//wait(&retCode);
//wait(&retCode);

int count=1;
char buffer[110];
i=0;
while(count)//stop the loop when count=0
{
  count=      read(fd[0], buffer, 100);
  buffer[count]='\0';
  printf("%s\n", buffer);

  i++;
  if (i%50==0)
    {
        usleep(200000);
    }


}


close(fd[0]);
close(fd[1]);
printf("DEBUG when ending A fd[0] is %d and fd[1] is %d\n", fd[0], fd[1]);

printf("Exiting A\n");

exit(EXIT_SUCCESS);

我遇到的问题是,在执行代码时,我的文件描述符 fd[0] 和 fd[1] 分别从 [3,4] 更改为 [0,0],尽管我显然没有操作它们。我遇到的教程都没有很好地解释这一点。

奇怪的是,如果我等待 b 和 c 终止,代码就会工作。 这是输出

  • 启动进程A,PID:27457
  • fork b 表示 fd[0] 为 3,fd[1] 为 4
  • fork 的 c 表示 fd[0] 为 3,fd[1] 为 4
  • 初始化字符串 b 后,fd[0] 为 0,fd[1] 为 0
  • 即将执行 B 且 fd[0] 为 0,fd[1] 为 0
  • 即将执行 execv C,fd[0] 为 0,fd[1] 为 0
  • 现在我们处于进程 C,pid:27459
  • 起始B
  • 将字符串导入B后,fd[0]为0,fd[1]为0
  • 退出 C
  • B 退出
  • B结束后,fd[0]为0,fd[1]为0
  • 当结束 A fd[0] 为 3 并且 fd[1] 为 4 时进行调试
  • 退出A

因此,当我们处于 fork 状态并操作字符串参数时,文件描述符有时会更改为零。请注意,这似乎发生在任一 execv 之前,因此我认为这是在子级的其他代码影响任何内容之前。

请注意,在使用 sprintf 将整数转换为字符串之前,整数本身为零。

据我所知,我没有在任何地方直接操作数组中的整数。因此,我最好的猜测是,管道在某个时刻被认为是关闭的,并且操作系统在发生这种情况时将所有文件描述符设置为零,但我很难详细找到该点。

我考虑过将 fd[] 文件描述符数组的元素保存为单独的整数,以避免指针出现问题,但我怀疑它们存储在数组中是有充分理由的。

我非常感谢有关该主题的任何建议!谢谢!

最佳答案

代码行

strArg[4] = NULL;

足以解释所有观察到的行为。该数组的尺寸为 4,这会覆盖末尾,并且可能会达到 fd 值。

修复该问题,如果不起作用,请重新提交您的问题。

strArg[3] = NULL;

关于c - 在c中使用pipe()时,我的文件描述符神秘地设置为零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22951932/

相关文章:

c - 忽略scanf的返回值

C:太大的堆栈会导致段错误吗?

java - 在 Android 上使用管道读取 shell 命令的输出

c - open() 和 fopen() 的应用

c - 使用文件描述符在 C 中读取文件

c++ - 当中断到来时如何退出 sleep()?

c - 跳过 C 语言中以逗号分隔的单词的第一行

c++ - 使用 cat 将数据文件通过管道传输到 C++ 程序

c - 将 STDOUT 重定向到文本文件无法正常工作

linux - 使用execve的困难