![](/img/trans.png)
[英]Unexpected behavior when printf is used after fork() and the parent is on wait()
[英]Printf and fork: wrong ordering, even when wait(NULL) is used
因此,我正在创建一个非常简单的外壳包装程序。 主进程使用readline读取一行,然后将其解析为char * [],然后由execvp处理。 Fork用于确保execvp运行后程序继续运行。 如果命令以&结尾,则母进程在继续之前不会等待派生完成。 如果结尾没有&,则母亲等待孩子完成。
一些代码:主要和接受输入功能
int main(){
//Welcome message
printf("Welcome to Bourne Shell Wrapper! Enter commands to run them, use ctrl+d to exit\n");
while(1){
//Prefering the complex readline over the easier scanf because of many functions that scanf does not offer.
char* line = readline("shw> ");
if (line == NULL) return 0;
struct Command command = parseInput(line);
if (command.params != NULL){
if (!runCommand(command)) return 1;
}
}
结构命令:
struct Command{
char async;
char** params;
};
运行命令的函数:
int runCommand(struct Command command){
//Fork, let the child run the command and the parent wait for the child to finish before returning
//The child has 0 as childPid, the mother has another positive value. Thats how we seperate them
pid_t childPid = fork();
if (childPid == -1){
printf("Failed to create child\n");
return 0;
} else if (childPid == 0){
if (execvp(command.params[0], command.params) == -1){
fprintf(stderr,"%s: ",strerror(errno));
printCommand(command);
}
return 1;
} else {
if (!command.async){
//This way the mother will wait until all her childeren are done before continuing
wait(NULL);
} else {
}
return 1;
}
}
所以,这就是问题所在。 当您不想异步时,这些东西就可以了:
Welcome to Bourne Shell Wrapper! Enter commands to run them, use ctrl+d to exit
shw> ls
debug Makefile obj release rpi-release src
shw>
正如预期的那样:母进程等待直到子进程返回,然后再次打印。 然后:
shw> ls &
shw> debug Makefile obj release rpi-release src
半预期的:由于父级继续运行而无需等待该过程,因此在ls输出之前会打印shw。 但是之后:
ls
shw> debug Makefile obj release rpi-release src
奇怪的! 父级应该等到子进程完成后才能重新打印shw>,但是它会在子级之前打印。
我不知道为什么会这样。 有人可以指出我正确的方向吗? 作为记录,无需使用&,一切正常。
您的评论说:
the mother will wait until all her childeren are done before continuing
但这不是事实。 wait()
等待一个孩子,无论哪个孩子先完成(包括一个在wait()
调用之前完成的孩子wait()
。
总结一下:执行异步命令时,您不必等待子进程完成; 当执行同步命令时,您等待一个孩子完成。 总而言之,您的wait()
少于创建的子级。
当您调用wait()
,您知道您正在等待一个特定的孩子,但是您没有告诉您wait
它,因此它将只等待第一个完成的孩子。 最终等待的孩子可能是先前发起的异步孩子,该孩子已经完成但状态尚未获得。
因此,这里有一个重要原则: 每个孩子都必须在某个时候获得收成。 如果您wait(2)
每个孩子wait(2)
,您将积累僵尸进程:实际上已经死了但仍在OS进程列表中的进程,因为它们的状态尚未恢复。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.