当我运行此代码时,是否有人知道为什么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退出”行。为什么会这样?
答案 0 :(得分:2)
你有三个错误。首先,用户在任何字母后输入的回车都算作输入。假设用户每行只输入一个字符,则fgets
调用将在返回您关注的字符和返回'\n'
之间切换。在每次迭代时,您需要读取并丢弃字符,直到到达每行输入的末尾。这就是导致双重打印输出的原因。
其次,您需要在<{1}}读取1>}并调用'q'
之间测试stdin
;现在,你在阅读fork
之后再次分叉。现在这是不可见的,但是一旦子进程开始做一些有用的东西,它就不会。
第三,如果用户输入 ^ D ,该程序将进入无限循环,因为您没有检查EOF。
将它们放在一起,更正的代码看起来像这样。我还修改了一些样式nits,并安排好父进程立即退出而不是退出'q'
循环;这意味着当控件到达标记有注释的点时,您知道自己处于子进程中,而不是在父进程中。
for
答案 1 :(得分:1)
当您在终端上键入x<enter>
时,您将获得(假设普通编码全部)两个字节发送到您的流程:一个用于x
,一个用于换行。
您的fgets
来电最多只读取一个字节(因此,x
),即时“死亡”的孩子的分叉,会打印消息并拨打fgets
。 fgets
选择它离开的位置:它不会阻塞地读取换行符,你的代码会无缘无故再次分叉,然后循环回来。
此时输入流中没有任何内容,因此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 } }
您可以让孩子调用另一个函数(例如程序包装器,甚至是非叉形版本),而不是破坏。等待将保持不变,即只等待一次所有叉子,好吧,分叉。