我正在试用一个开放课程的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);
}
奇怪的是,当我执行&#34; ls |时排序&#34;在终端中,我不断得到以下输出
6.828$ ls | sort
6.828$ a.out
sh.c
t.sh
这表示在下一个命令提示符之前&#34; 6828 $&#34;打印时,子进程的输出仍然没有刷新到终端。
但是,如果我不使用 pid = waitpid(-1,&amp; r,WNOHANG))并使用 pid = waitpid(-1,&amp; r, 0))(或 wait()),输出正常如下:
6.828$ ls | sort
a.out
sh.c
t.sh
我长期以来一直在考虑问题的原因,但没有提出可能的原因。任何人都可以提出一些可能的原因吗?
非常感谢!
答案 0 :(得分:1)
此代码没有明确定义的行为:
while ((pid = waitpid(-1, &r, WNOHANG)) >= 0) {
if (errno == ECHILD) {
break;
}
}
如果while
返回-1,waitpid
循环会立即中断,这正是错误情况下返回的内容。因此,如果输入循环体,waitpid
返回一些非负值:0表示孩子仍在执行 - 或者已经退出的孩子的pid。这些不是错误条件,因此errno
的值没有意义。它可能是ECHILD
,在这种情况下,循环将错误地中断。
必须仅在值有意义的情况下检查errno
的值。或者,更准确地说,引用Posix standard:
errno
的值只能在调用明确声明为其设置的函数之后定义,并且直到它被下一个函数调用更改或者应用程序为其赋值。errno
的值只有在函数的返回值被指示有效时才应进行检查。
但是我很困惑为什么你认为有必要使用WNOHANG
进行忙碌循环。这是一个巨大的资源浪费,因为您的父进程将重复执行系统调用,直到子实际终止。由于您真的打算等到孩子终止,因此只需拨打wait
或将0
指定为waitpid
的标记值就更有意义了。
另一方面,如果wait
(waitpid
返回-1且errno
设置为EINTR
,则可能需要重复-1
(或errno
)。如果它返回EINTR
且ECHILD
既不是 <table class="table table-striped">
@foreach($users as $user)
<form method="POST" action="your_controller_function_route">
<tr>
<td class="col-md-2">
{!! $user->id !!}
</td>
<td class="col-md-2">
{!! $user->name !!}
</td>
<td class="col-md-2">
<input type="hidden" name="email" value="{!! $user->email !!}"> {!! $user->email !!}
</td>
<td class="col-md-3">
<input type="submit" id ="sub{{ $user->id }}" class="btn btn-success btn-md" value="GET VALUE">
</td>
</tr>
</form>
@endforeach
</table>
也不是{{1}},那么您可能想要记录一些硬错误。但那与你的问题没有关系,afaics。