【发布时间】:2017-05-17 01:42:33
【问题描述】:
我正在从一门开放课程中尝试 C shell 实现,但输出缓冲的行为有些有趣。
代码是这样的(注意我使用 pid = waitpid(-1, &r, WNOHANG) 的那一行):
int
main(void)
{
static char buf[100];
int fd, r;
pid_t pid = 0;
// Read and run input commands.
while(getcmd(buf, sizeof(buf)) >= 0){
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
buf[strlen(buf)-1] = 0; // chop \n
if(chdir(buf+3) < 0)
fprintf(stderr, "cannot cd %s\n", buf+3);
continue;
}
if((pid = fork1()) == 0)
runcmd(parsecmd(buf));
while ((pid = waitpid(-1, &r, WNOHANG)) >= 0) {
if (errno == ECHILD) {
break;
}
}
}
exit(0);
}
runcmd函数是这样的(注意在管道处理中我创建了2个子进程并等待它们终止):
void
runcmd(struct cmd *cmd)
{
int p[2], r;
struct execcmd *ecmd;
struct pipecmd *pcmd;
struct redircmd *rcmd;
if(cmd == 0)
exit(0);
switch(cmd->type){
case ' ':
ecmd = (struct execcmd*)cmd;
if(ecmd->argv[0] == 0) {
exit(0);
}
// Your code here ...
// fprintf(stderr, "starting to run cmd: %s\n", ecmd->argv[0]);
execvp(ecmd->argv[0], ecmd->argv);
fprintf(stderr, "exec error !\n");
exit(-1);
break;
case '>':
case '<':
rcmd = (struct redircmd*)cmd;
// fprintf(stderr, "starting to run <> cmd: %s\n", rcmd->file);
// Your code here ...
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
if (rcmd->type == '<') {
// input
close(0);
if (open(rcmd->file, O_RDONLY, mode) != 0) {
fprintf(stderr, "Opening file error !\n");
exit(-1);
}
} else {
// output
close(1);
if (open(rcmd->file, O_WRONLY|O_CREAT|O_TRUNC, mode) != 1) {
fprintf(stderr, "Opening file error !\n");
exit(-1);
}
}
runcmd(rcmd->cmd);
break;
case '|':
pcmd = (struct pipecmd*)cmd;
// fprintf(stderr, "starting to run pcmd\n");
// Your code here ...
pipe(p);
if (fork1() == 0) {
// child for read, right side command
close(0);
if (dup(p[0]) != 0) {
fprintf(stderr, "error when dup !\n");
exit(-1);
}
close(p[0]);
close(p[1]);
runcmd(pcmd->right);
fprintf(stderr, "exec error !\n");
}
if (fork1() == 0) {
// left side command for writing
close(1);
if (dup(p[1]) != 1) {
fprintf(stderr, "dup error !\n");
exit(-1);
}
close(p[0]);
close(p[1]);
runcmd(pcmd->left);
fprintf(stderr, "exec error !\n");
}
close(p[0]);
close(p[1]);
int stat;
wait(&stat);
wait(&stat);
break;
default:
fprintf(stderr, "unknown runcmd\n");
exit(-1);
}
exit(0);
}
奇怪的是,当我在终端中执行“ls | sort”时,我不断得到以下输出
6.828$ ls | sort
6.828$ a.out
sh.c
t.sh
这表示在打印下一个命令提示符“6828$”之前,子进程的输出仍未刷新到终端。
但是,如果我不使用 pid = waitpid(-1, &r, WNOHANG)) 并使用 pid = waitpid(-1, &r, 0)) (或wait()),输出会是正常的,如:
6.828$ ls | sort
a.out
sh.c
t.sh
我一直在思考问题的原因,但没有想出可能的原因。谁能提出一些可能的原因?
非常感谢!
【问题讨论】: