Завершение фонового процесса на следующем процессе переднего плана - PullRequest
0 голосов
/ 07 октября 2018

У меня проблемы с циклом в моей оболочке и прекращением фонового процесса.Я не могу понять, как правильно использовать waitpid после того, как часами посмотрел на несколько таких вопросов, поэтому опишу свою проблему.

Мне нужно несколько секунд запустить команду сна, сохранив этоpid, выполните команду ls и оставьте мою оболочку включенной, пока сон работает в фоновом режиме.Следующий процесс переднего плана, который выполняется, (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;
                    }
                }
            }
}

, но оболочка просто запускает процесс, зависает и никогда не дает мне собранного сообщения.В этом случае, когда я нажму 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

(я нажимаю ввод или любой ввод здесь, в противном случае подсказка отсутствует)

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