首页 > 解决方案 > 在下一个前台进程中终止后台进程

问题描述

我在循环我的 shell 和终止后台进程时遇到了麻烦。在看了几个小时这样的问题后,我无法弄清楚 waitpid 的正确用法,所以我将描述我的问题。

我需要运行一个 sleep 命令几秒钟,保存那个 pid,运行一个 ls 命令并在 sleep 在后台运行时保持我的 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;
                    }
                }
            }
}

但是外壳程序只是运行该过程,挂起并且从未给我一个收获的消息。在那种情况下,当我按下回车键时,它会将父进程重新启动到循环的顶部,但永远不会收获后台进程。我到底做错了什么?我尝试使用 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

(我在这里按回车键或任何输入,否则没有提示)

Freeing input...
backgroundPid - 9886
looping...
shellProg> 

标签: cforkbackground-process

解决方案


推荐阅读