C Printf和fork:错误的排序,即使使用了wait(NULL)
所以我创建了一个非常简单的shell包装器。主进程使用readline读取一行,然后将其解析为char*[],然后由execvp处理。Fork用于确保程序在execvp运行后继续运行。如果命令以&结束,则母进程在继续之前不会等待fork完成。如果最后没有&则母亲等待孩子完成 一些代码: 主要功能和输入接受功能C Printf和fork:错误的排序,即使使用了wait(NULL),c,linux,bash,C,Linux,Bash,所以我创建了一个非常简单的shell包装器。主进程使用readline读取一行,然后将其解析为char*[],然后由execvp处理。Fork用于确保程序在execvp运行后继续运行。如果命令以&结束,则母进程在继续之前不会等待fork完成。如果最后没有&则母亲等待孩子完成 一些代码: 主要功能和输入接受功能 int main(){ //Welcome message printf("Welcome to Bourne Shell Wrapper! Enter commands
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;
}
}
所以,问题出在这里。当您不想进行异步时,这些功能可以正常工作:
欢迎使用Bourne Shell包装器!输入运行命令,使用ctrl+d退出
shw>ls
调试Makefile obj release rpi release src
shw>
正如预期的那样:在再次打印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
,所以它只会等待哪个孩子先完成。它最终等待的子对象很可能是先前启动的异步子对象,该子对象已完成,但其状态尚未恢复
所以这里有一个重要的原则:每个孩子都必须在某个时候收获。如果不为每个子进程等待(2)
,则会累积僵尸进程:实际上已死亡但仍在操作系统进程列表中活动的进程,因为尚未检索它们的状态