【问题标题】:How to make a UNIX pipe prompt for user input correctly?如何正确提示用户输入的 UNIX 管道?
【发布时间】:2013-05-20 23:56:12
【问题描述】:

我正在尝试让 UNIX 管道正确提示用户输入。我必须使用单个管道创建 3 个子进程。每个子进程要求用户输入一个整数并将其写入管道。父进程显示所有三个整数以及将每个整数写入管道的进程的 processid。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char argv[]) {
    int input = 0;
    int pd[2];
    int i =0;
    int buffer[100];
    int output = 0;

    if (pipe(pd) == - 1) {
        fprintf(stderr, "Pipe Failed");
    }

    for (i=0; i<3; i++) {
        if (fork() == 0) { // child process
            printf("\nMy process id is: %d", getpid());
            printf("\nEnter an integer: ");  
            scanf("%d", &input);
            if (write(pd[1], &input, sizeof(int)) == -1) {
                fprintf(stderr, "Write Failed");
            }
            return (0); // Return to parent. I am not really sure where this should go 
        } // end if statement
    } // I am not quite sure where the for loop ends

    // Parent process
    close(pd[1]); // closing the write end

    for (i = 0; i < 3; i++) {
        if (read(pd[0], &output, sizeof(int) )== -1) {
            fprintf(stderr, "Read failed"); 
        }
        else {
            buffer[i] = output;
            printf("Process ID is: %d\n", pid);
        }
    } 
    printf("The numbers are %d, %d, %d", buffer[0], buffer[1], buffer[2]);
    return(0);
}

编辑后,我现在得到输出:

My process id is: 2897
Enter an integer: My process id is: 2896
Enter an integer: 
My process id is: 2898
Enter an integer: 4
Process ID is: 2898
78
Process ID is: 2898
65
Process ID is: 2898
The numbers are 4, 78, 65

这更接近,但我还不确定如何让父进程等待子进程。当尝试打印每个数字及其进程 ID 时,只会打印最新的进程 ID。

所有的 printf 语句都在 scanf 语句之前执行,所以在它提示 3 次之前我不能输入任何内容。

【问题讨论】:

  • 您已授予三个独立且不协调的进程对终端的无信号访问权限。 当然他们交错输入和输出:这就是你告诉他们要做的。

标签: c unix pipe


【解决方案1】:
if (read(pd[0]), &output, sizeof(int) )== -1)
              ^ // this is wrong

您的括号不正确,但我认为这是一个错字。

只有在读取失败时才更新缓冲区...应该是:

if (read(pd[0], &output, sizeof(int) )== -1) {
    fprintf(stderr, "Read failed");
}
else {
    buffer[i] = output;
}

不过,有很多方法可以改进此代码。查看其他答案并在 (-Wall with gcc) 上编译带有警告的程序

【讨论】:

  • 谢谢。不敢相信我完全忽略了这一点。我改变了它,数字显示正确。我已经修正了错字,但忘了在这里更新它。我现在编辑了这个问题。我查看了其他答案,几乎所有答案都涉及使用 dup 函数的多个管道,而我还没有达到那个水平。您能否解释一下我的代码还有哪些可以改进的地方(如果您不介意的话)。谢谢。
【解决方案2】:

在任何给定时间,只有一个进程可以与用户交谈。您需要安排孩子 2 在孩子 1 完成之前不做任何事情,依此类推。最简单的方法是让每个孩子的父 wait() 连续,然后再分叉下一个。 编辑:看起来像这样:

for (i = 0; i < 3; i++) {
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        return 1;
    } else if (pid == 0) {
        // your existing child code goes here
    } else {
        // parent:
        int status;
        if (waitpid(pid, &status, 0) != pid) {
            perror("wait");
            return 1;
        } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
            fprintf(stderr, "child %d unexpected exit %d\n", i, status);
            return 1;
        }
    }
}

由于写入管道的数据量非常短(总共小于 PIPE_BUF 字节;PIPE_BUF 保证至少为 512),您可以放心地延迟从管道读取,直到所有孩子都拥有退出。如果孩子们发回更长的消息,情况就不是这样了。

main 返回一个整数。您在第一个循环中的return; 语句应该是return 0;,并且最后需要有另一个return 0;(在最后一个printf 之后)。

你的第一个for 循环在它应该结束的地方结束,即在嵌套的if 语句之后。您可以在其周围放置另一组花括号 - 在 for (...) 之后打开大括号,在有 // I am not quite sure 评论的地方关闭大括号 - 很多人会认为更好的样式,但是你不必这样做。

【讨论】:

  • 在使用 for 循环时,子进程的父进程 wait() 在哪里?我想我可以 fork() 一个子进程,然后 wait() 并再次 fork 它,但这需要我放弃 for 循环并复制粘贴子进程三次(除非我错过了更好的方法)。另外,为什么输出显示的是奇怪的数字而不是我输入的数字?我认为它们是数字的地址,但如果我取消引用它们,编译器会说我正在从没有强制转换的整数中创建指针。
  • 我在我的答案中编辑了一个示例 fork-and-wait 循环。 Guillaume 似乎已经解决了您奇怪的数字问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-10
  • 2013-04-30
  • 2015-06-24
  • 1970-01-01
  • 2022-01-27
相关资源
最近更新 更多