我在遍历外壳程序和终止后台进程时遇到麻烦。在看了几个小时的此类问题后,我无法弄清楚waitpid的正确用法,因此我将描述问题。
我需要运行sleep命令几秒钟,保存该pid,运行ls命令并在休眠在后台运行时保持我的shell运行。接下来执行的下一个前台进程(ls)之后将在执行后清除后台进程。所以我写了这样的东西
while(1) {
//Prompt user input
//Get input from user
//Parse & tokenize
//Determine if this process is to run in the background
if((strcmp(symbols[0], "&") == 0) || (strcmp(symbols[0], "&\n") == 0)) {
backgroundFlag = true;
} else {
backgroundFlag = false;
foregroundFlag = true;
}
pid_t childPid = fork();
if(backgroundFlag == true && childPid != 0) {
backgroundPid = childPid;
}
//Determine the process
if(childPid == 0) {
//Run in the background
if(backgroundFlag == true) {
printf(">>>IN CHILD(background): backgroundPid = %d\n", getpid());
backgroundPid = getpid();
} else {
foregroundFlag = true;
//debug
printf("\n>>>IN CHILD: pid = %d\n", getpid());
}
//Save this for child pid
childPid = getpid();
//Execute the command
execvp(command1[0], args1-1);
} else {
printf("\n>>>In Parent: pid = %d\n", getpid());
//this is the parent
if(backgroundFlag == false && backgroundPid == 0) {
wait(NULL);
foregroundFlag = false;
printf("\n...Child reaped: pid = %d\n", childPid);
} else if (backgroundFlag == true && backgroundPid > 0) {
pid_t return_pid = waitpid(backgroundPid, 0, WNOHANG);
if(return_pid == backgroundPid) {
printf("\n...background child reaped: pid = %d\n", backgroundPid);
backgroundPid = 0;
}
}
}
}
但是shell只是运行进程,挂起并且从不给我任何消息。在这种情况下,当我按Enter键时,它将重新启动父级,直到循环的顶部,但绝不会收获后台进程。我到底在做什么错?我尝试使用backgroundPid和-1,WNOHANG和其他一些标志进行循环,但是我一直在获取相同的内容-它会运行并挂起,直到再次按Enter才再次提示输入,否则它将首先运行并且不允许任何输入其他需要处理的前景。
无论哪种方式,它都不会收获背景。
这是我通过执行sleep(3)和(这是回显的自定义睡眠)而得到的结果,然后在完成前显示ls,然后再次显示ls
progShell> ./customecho testing &
COMMAND #1: ./customecho
...The above command will be executed in background
>>>In Parent: pid = 7774
Freeing input...
backgroundPid - 7793
looping...
>>>IN CHILD(background): backgroundPid = 7793
progShell> ls
COMMAND #1: ls
>>>In Parent: pid = 7774
Freeing input...
backgroundPid - 7793
looping...
progShell>
>>>IN CHILD: pid = 7794
Makefile progShell progShell.c customecho.c customecho
customecho PID=7793: testing
然后只有在按ENTER键后我才能得到此信息... 没有终止...
Freeing input...
backgroundPid - 7793
looping...
编辑:播放了一段时间,并设法修复了一些代码-
while(1) {
//Determine if this process is to run in the background
if((strcmp(symbols[0], "&") == 0) || (strcmp(symbols[0], "&\n") == 0)) {
backgroundFlag = true;
backgroundFinishedFlag = false;
} else {
backgroundFlag = false;
foregroundFlag = true;
}
printf("Background finished: %d\n", backgroundFinishedFlag);
printf("Background flag: %d\n", backgroundFlag);
//Create a new process
pid_t childPid = fork();
//Determine if this process is to run in the background, and assign appropriately per process.
if(backgroundFlag == true && childPid == 0) {
backgroundPid = getpid();
printf("Background process (PID=%d)\n", backgroundPid);
} else if(backgroundFlag == true) {
backgroundPid = childPid;
}
//Determine the process we are in - this is child
if(childPid == 0) {
//debug
//Run in the background
if(backgroundFlag == true) {
printf(">>>IN CHILD(background): backgroundPid = %d\n", getpid());
} else {
//Run in the foreground
printf("\n>>>IN CHILD: pid = %d\n", getpid());
}
//Save this for child pid
childPid = getpid();
//Execute the command
execvp(command1[0], args1-1);
} else {
//this is the parent
//debug
printf("\n>>>In Parent: pid = %d\n", getpid());
printf("\t this parent's child is - %d and background id is %d\n", childPid, backgroundPid);
//There is a foreground process - execute it first.
if(foregroundFlag) {
waitpid(childPid, NULL, 0);
foregroundFlag = false;
printf("\n...Child reaped: pid = %d\n", childPid);
}
//Determine if there is a background process to be reaped
if(backgroundFinishedFlag == false && backgroundPid > 0 && (waitpid(backgroundPid, NULL, WNOHANG) > 0)) {
printf("\nTerminating background process now!\n");
backgroundFinishedFlag = true;
backgroundPid = 0;
}
}
}
它在下一个前台进程完成时在后台终止子进程... 唯一的问题是,后台进程完成后,我希望它再次提示输入-我可以使用任何信号捕获来执行此操作吗?例如...休眠打印后,它将覆盖看起来像输入的“ shellProg>”提示,并留出空白空间供输入。
shellProg> sne PID=9886: testing
(我按Enter或此处的任何输入,否则无提示)
Freeing input...
backgroundPid - 9886
looping...
shellProg>