fork()系统调用和while循环(第2部分)

时间:2013-10-23 18:01:17

标签: c linux fork system-calls

当我运行此代码时,是否有人知道为什么printf(“键入q退出”)行在终端中打印两次:

#include <stdio.h>
#include <unistd.h>

int main (int argc, char *argv[])
{
    char run[2];
    run[0]='a';
    int pid=0;
    while (run[0]!= 'q')    
    {
        printf("Type q to quit \n");
        fgets (run, 2, stdin);

        pid=fork();
        //wait();
        if(pid==0) { break;}
    }
}

我希望孩子从循环中断开,父母继续循环(创建新孩子)。如果我调用wait(),则执行在第一次迭代后结束,无论是否输入“q”。否则它按预期工作,但每次打印两次“键入q退出”行。为什么会这样?

3 个答案:

答案 0 :(得分:2)

你有三个错误。首先,用户在任何字母后输入的回车都算作输入。假设用户每行只输入一个字符,则fgets调用将在返回您关注的字符和返回'\n'之间切换。在每次迭代时,您需要读取并丢弃字符,直到到达每行输入的末尾。这就是导致双重打印输出的原因。

其次,您需要在<{1}}读取}并调用'q'之间测试stdin ;现在,你在阅读fork之后再次分叉。现在这是不可见的,但是一旦子进程开始做一些有用的东西,它就不会。

第三,如果用户输入 ^ D ,该程序将进入无限循环,因为您没有检查EOF。

将它们放在一起,更正的代码看起来像这样。我还修改了一些样式nits,并安排好父进程立即退出而不是退出'q'循环;这意味着当控件到达标记有注释的点时,您知道自己处于子进程中,而不是在父进程中。

for

答案 1 :(得分:1)

当您在终端上键入x<enter>时,您将获得(假设普通编码全部)两个字节发送到您的流程:一个用于x,一个用于换行。

您的fgets来电最多只读取一个字节(因此,x),即时“死亡”的孩子的分叉,会打印消息并拨打fgetsfgets选择它离开的位置:它不会阻塞地读取换行符,你的代码会无缘无故再次分叉,然后循环回来。
此时输入流中没有任何内容,因此fgets等待I / O.

例如,请参阅:I am not able to flush stdin了解“清除”您可以在此处使用的输入流的方法。

答案 2 :(得分:0)

您需要等待这些分叉流程:

   int main (int argc, char *argv[])
   {
    char run[2];
    run[0]='a';
    int pid=0;
    int pids[256]; // should be enough.
    int j,i = 0;

    while (run[0]!= 'q')    
    {
        printf("Type q to quit \n");
        fgets (run, 2, stdin);

        pid=fork();
        //wait();
        if(pid==0) { break;}
        else { pids[i] = pid; i++; }
    }
    for (j = 0 ; j < i && pid != 0 ; j++)
       wait(pids[j]);
      if(pid == 0){
         // do something
      }

   }

您可以让孩子调用另一个函数(例如程序包装​​器,甚至是非叉形版本),而不是破坏。等待将保持不变,即只等待一次所有叉子,好吧,分叉。