当前位置: 首页 > 知识库问答 >
问题:

如何用fork()从Stdin读取输入

国兴文
2023-03-14

我想从STDIN读取输入。我在C中使用fork()方法。我有子进程和父进程。我的输入是多行的。父进程只等待子进程终止,子进程只读取第一行,子进程终止后,父进程继续读取。我想要打印行。例如;输入->

    null

子进程打印“星期一”,父进程打印“星期二”和“星期三”。一旦到达文件结尾,程序就会终止。

./program

共有1个答案

陈琪
2023-03-14

好;听起来很直截了当--至少,只要你在输入。事实上,很难让它出错。你尝试了什么,当你尝试的时候发生了什么?请阅读如何创建一个MCVE(最小的,完整的,可验证的例子)。

然而,当您从文件中读取时,它会变得(很多)棘手。问题是,当您从终端读取数据时,子级中的标准I/O例程会获得第一行数据,然后让进程处理这些数据。孩子不读第二行就退出了,所以家长可以从孩子停下来的地方开始。相反,如果从文件中读取,标准I/O例程将读取一个充满数据的缓冲区,其中可能有许多行。而孩子读的东西,家长不能读。因此,与终端输入一起工作的东西不能与文件输入一起工作。

你怎样才能避免这个问题?很难。一种可能被认为是作弊的可能性是在分叉之前让初始(父)进程读取一个字符。如果输入来自终端,则用一行填充缓冲区;如果从文件读取,则用初始缓冲区填充。分叉之后,子进程可以读取第一行(fgets())并打印它,然后退出。同时,父进程在其输入缓冲区副本中也有第一行数据(请记住,分叉后分叉的子进程和父进程几乎相同),因此它可以读取并忽略第一行(子进程正在处理它),然后读取并打印其余的行。然后它可以在循环中等待孩子死亡,最后读取剩余的行。这导致:

/* SO 4263-5451 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    pid_t pid;
    int c = getchar();
    if (c == EOF)
    {
        fprintf(stderr, "Standard input was empty!\n");
        exit(1);
    }
    ungetc(c, stdin);
    //setvbuf(stdin, 0, _IOLBF, 0);

    if ((pid = fork()) < 0)
    {
        fprintf(stderr, "Failed to fork()!\n");
        exit(2);
    }
    if (pid == 0)
    {
        /* Child */
        char line[4096];
        if (fgets(line, sizeof(line), stdin) == 0)
        {
            fprintf(stderr, "Failed to read line in child\n");
            exit(3);
        }
        line[strcspn(line, "\n")] = '\0';
        printf("Child: read [%s]\n", line);
        exit(0);
    }
    else
    {
        int corpse;
        int status;
        while ((corpse = wait(&status)) > 0 && corpse != pid)
            printf("Parent: child %d died with status 0x%.4X\n", corpse, status);
        char line[4096];
        if (fgets(line, sizeof(line), stdin) == 0)
        {
            fprintf(stderr, "Failed to read line in parent\n");
            exit(4);
        }
        while (fgets(line, sizeof(line), stdin) != 0)
        {
            line[strcspn(line, "\n")] = '\0';
            printf("Parent: read [%s]\n", line);
        }
    }
    return 0;
}
Child: read [Monday]
Parent: read [Tuesday]
Parent: read [Wednesday]

我尝试了使用setvbuf(stdin,0,_iolbf,0);设置行缓冲的变体,但这并不影响文件输入(在运行带有GCC 6.3.0的macOS Sierra 10.12.3的Mac上),尽管它也能很好地处理终端输入。

一种选择是用文件描述符代码替换标准I/O函数,并使用read(STDIN_FILENO,&c,1)一次读取一个字符。这是较慢的(大量系统调用),但可靠的:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

static int input_char(int fd)
{
    char c;
    if (read(fd, &c, 1) != 1)
        return EOF;
    return c;
}

static size_t input_line(int fd, char *buffer, size_t buflen)
{
    int c;
    size_t bufcnt = 0;
    while (bufcnt < buflen - 1 && (c = input_char(fd)) != EOF)
    {
        if (c == '\n')
            break;
        buffer[bufcnt++] = c;
    }
    buffer[bufcnt] = '\0';
    return bufcnt;
}

int main(void)
{
    pid_t pid;

    if ((pid = fork()) < 0)
    {
        fprintf(stderr, "Failed to fork()!\n");
        exit(2);
    }
    if (pid == 0)
    {
        char line[4096];
        if (input_line(STDIN_FILENO, line, sizeof(line)) == 0)
        {
            fprintf(stderr, "Failed to read line in child\n");
            exit(3);
        }

        printf("Child: read [%s]\n", line);
        exit(0);
    }
    else
    {
        int corpse;
        int status;
        while ((corpse = wait(&status)) > 0 && corpse != pid)
            printf("Parent: child %d died with status 0x%.4X\n", corpse, status);
        char line[4096];
        while (input_line(STDIN_FILENO, line, sizeof(line)) != 0)
        {
            printf("Parent: read [%s]\n", line);
        }
    }
    return 0;
}
 类似资料:
  • 问题内容: 是否可以在正在运行的nodejs脚本中侦听传入的击键?如果我使用并监听其事件,则输入将被缓冲到下一个换行符,如下所示: 运行此,我得到: 我想要看的是: 我正在寻找一个等效于例如ruby的nodejs 这可能吗? 问题答案: 如果切换到原始模式,则可以通过这种方式实现:

  • 问题内容: 当有字符可用时,是否有一种优雅的方法来触发事件?我想避免投票。 问题答案: 您将必须创建一个单独的线程以阻止读取,直到有可用的线程为止。 如果您不想实际消耗输入,则必须用内部缓冲区包装它,读入缓冲区,然后喊叫,并在要求输入时从缓冲区返回数据。 您可以这样解决:

  • 问题内容: 是否可以从node.js中的stdin同步读取?因为我正在用JavaScript编写JavaScript编译器,所以很有趣。Brainfuck支持需要同步执行的读取操作。 我尝试了这个: 但这只会产生以下输出: 问题答案: 我不知道什么时候出现,但这是向前迈出的有益一步:http : //nodejs.org/api/readline.html 现在,我可以一次从stdin中读取行。快

  • 问题内容: 我正在使用以下命令行调用来处理带有node的文本文件: 文件的每一行都需要单独处理,但是一旦处理完,输入行可能会被忘记。 使用标准输入的数据侦听器,我得到了按字节大小分块的输入流,因此进行了设置。 但这似乎草率。必须在行数组的第一项和最后一项周围进行按摩。有没有更优雅的方式做到这一点? 问题答案: 您可以使用readline模块逐行从stdin进行读取:

  • 问题内容: 我想阅读Go程序的原始内容。例如,如果我这样做了,我希望可以访问“ test stdin”。我尝试从中读取,但是如果其中没有任何内容,则它将等待输入。我也尝试过先检查大小,但是即使输入传入也为0。 我能做什么? 问题答案: 我认为您的问题本身没有明智的答案,因为没有“初始标准输入”之类的东西。类似于Unix的操作系统和Windows都实现了“标准流”的概念,它的工作原理如下(简化):创

  • 问题内容: 从标准输入逐行读取的Scala配方是什么?类似于等效的Java代码: 问题答案: 最直接的前瞻性的方式将只使用它的一部分。但是,这很丑陋,因为您需要检查最终的空值: 这太冗长了,您宁可使用它。 我认为将使用更漂亮的方法: