在C语言中,我可以使用wait(&status)和loop清理具有相同父进程的多个子进程吗?

idv4meu8  于 2023-01-29  发布在  其他
关注(0)|答案(2)|浏览(161)

我正在编写一个程序,可以从文件中读取linux命令,并使用fork()execvp()并行运行它们,它工作得很好。

while((current = GetNextCommand(current)) != NULL){
            char currentCommand[WIDTH - 1];
            current->active = true;
            strcpy(currentCommand, current->command);
            int j=0;
            int ctr=0;
            char newString[LENGTH][WIDTH];
            for(int i = 0; i <= strlen(currentCommand); i++){
                // if space or NULL found, assign NULL into newString[ctr]
                if(currentCommand[i]==' '|| currentCommand[i]=='\0')
                {
                    newString[ctr][j]='\0';
                    ctr++;  //for next word
                    j=0;    //for next word, init index to 0
                }
                else
                {
                    newString[ctr][j] = currentCommand[i];
                    j++;
                }
            }
            char *exe[ctr + 1];
            for(int i = 0; i < ctr; i++){
                exe[i] = strdup(newString[i]);
            }
            exe[ctr] = NULL;
            t = clock();
            clock_gettime(CLOCK_MONOTONIC, &start);
            current->starttime = start.tv_sec;
            current->PID = (pid = fork());
            if(pid < 0){
                fprintf(stderr, "fork Failed\n"); //output in stderr if fork fails and return
                exit(1);
            }
            else if(pid == 0){
                execvp(exe[0], exe);
                //fails
                exit(2);
            }
        }

我的档案是

sleep 3
ls -latr
sleep 1
pwd
sleep 1
wc /etc/passwd
sleep 10

在父进程中,我需要获取每个子进程的运行时间,如果命令的运行时间大于2秒,我将重新运行该命令,如果命令的运行时间大于2秒,我将继续运行该命令,直到用户使用kill -sig pidpkill sleep杀死该进程。我使用for循环,并设置相应的等待数(&status).在我的文件中,sleep 3sleep 10将大于2秒,当sleep 3的进程完成工作后,它将返回父进程,sleep 10仍在运行,当我现在使用pkill sleep时,它将很好,因为sleep 10将继续在父进程中运行,但是,当它们都从子进程中退出,而我使用kill -sig pid时,整个程序退出。那么,在这种情况下,我如何同时运行它们(sleep 3sleep 10)呢?

for(int i = 0; i < nodeIndex - 1; i++){
    int status;
    int pid = wait(&status);
    clock_gettime(CLOCK_MONOTONIC, &finish);
    CommandNode* cNode;
    cNode = FindCommand(head->nextCommandPtr, pid);
    elapsed = finish.tv_sec - cNode->starttime;
    printf("%ld\n", elapsed);
    if(elapsed < 2){
        cNode->active = false;
    }
    else{
        char rerunCommand[WIDTH - 1];
        strcpy(rerunCommand, cNode->command);
        int j=0;
        int ctr=0;
        char newString[LENGTH][WIDTH];
        for(int i = 0; i <= strlen(rerunCommand); i++){
            // if space or NULL found, assign NULL into newString[ctr]
            if(rerunCommand[i]==' '|| rerunCommand[i]=='\0')
            {
                newString[ctr][j]='\0';
                ctr++;  //for next word
                j=0;    //for next word, init index to 0
            }
            else
            {
                newString[ctr][j] = rerunCommand[i];
                j++;
            }
        }
        char *exe[ctr + 1];
        for(int i = 0; i < ctr; i++){
            exe[i] = strdup(newString[i]);
        }
        exe[ctr] = NULL;
        while(elapsed > 2){
            int pid2;
            t = clock();
            clock_gettime(CLOCK_MONOTONIC, &start);
            cNode->starttime = start.tv_sec;
            cNode->PID = (pid2 = fork());
            if(pid2 < 0){
                fprintf(stderr, "fork Failed"); //output in stderr if fork fails and return
                exit(1);
            }
            else if(pid2 == 0){
                printf("What happened here.\n");
                execvp(exe[0], exe);
                exit(2);
            }
            else{
                wait(&status);
                clock_gettime(CLOCK_MONOTONIC, &finish);
                elapsed = finish.tv_sec - cNode->starttime;
                if(elapsed > 2) {
                    printf("What is this: %d %d\n", pid2, cNode->PID);
                }
            }
        }
    }
}
m2xkgtsf

m2xkgtsf1#

关于标题中的问题:
是的,你可以,只是循环,直到返回值是-1

py49o6xq

py49o6xq2#

是的,这确实是一个正确的方法,以确保您所有的孩子已经完成之前,您继续:

pid_t pid;
...
while((pid = wait(NULL)) >= 0)
    printf("child pid=%d ended.\n", pid); /* or whatever you want */

/* no more children active after this point, you don't need 
 * to check the value of errno, except if you allow this
 * process to be interrupted by a signal. */

这是僵尸进程的旧遗产(就像行尸走肉电影的片名):僵尸进程是一个进程,它已经exit(2)艾德但是它的父进程还没有wait(2)。除了它的进程表条目(其中存储了它的退出代码和记帐记录)之外,它释放了它的所有资源。这样,当父进程执行wait(2)系统调用时,内核可导航其子进程的表并检查其是否必须返回错误(如果列表为空),或者某个子进程已经结束,可以将它的exit(2)代码返回给父进程。只有在您以前创建过fork(2)的情况下,才能正确使用wait(2)(例如,没有错误)。并且wait(2)在您没有创建子进程的情况下发出错误信号。
要获得子进程的运行时间,您需要使用wait(2)的一个备用系统调用(wait3(2)wait4(2),根据FreeBSD手册页,Linux上有类似的系统调用)
试试这个简单的例子:

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

#define N                    7
#define PARENT_SLEEP        30
#define CHILD_MAXSLEEP      60

int main()
{
    int i;
    pid_t mypid = getpid();

    for(i = 0; i < N; i++) {

        pid_t chpid = fork();

        switch (chpid) {

        case -1: /* error */
            fprintf(stderr,
                "Parent [pid=%d]: fork: %s\n",
                mypid,
                strerror(errno));
            goto out; /* we want to break the loop */

        case 0: /* child */
            /* reinit mypid to reflect proper value */
            mypid = getpid();

            printf("Child [pid=%d]: start\n", mypid);

            /* we initialize random module after fork, so
             * all children don't get the same random
             * sequence. Probably all of them will take
             * the same value for the time, so we use also
             * the pid for the seed to be different for
             * each child. */
            srandom( mypid ^ time(NULL) );

            /* a random time between 1 and CHILD_MAXSLEEP */
            int myrandom = random() % CHILD_MAXSLEEP + 1;
            printf("Child [pid=%d]: wait for %d secs.\n",
                    mypid, myrandom);
            sleep( myrandom );

            printf("Child [pid=%d]: exiting with code=%d\n",
                mypid, myrandom);
            exit( myrandom );

        default: /* parent */
            printf("Parent[pid=%d]: I have started"
                    " child (pid = %d)\n", mypid, chpid);
            break;
        } /* switch */
    } /* for */

out:
    /* if you put a delay here, before doing wait()s,
     * and you execute a ps(1) command before the parent
     * begins to make waits, and some of the children have
     * already died, you'll see the zombie processes
     * (they are marked with a Z in status) */
    printf("Parent [pid=%d]: sleeping for %ds.\n",
            mypid, PARENT_SLEEP);
    sleep(PARENT_SLEEP);
    printf("Parent [pid=%d]: beginning to wait.\n",
            mypid);

    int status;
    pid_t child;

    while ((child = wait(&status)) >= 0) {
        printf("Parent[pid=%d]: "
                "detected exit(%d) from "
                "child(pid=%d)\n",
                mypid,
                WEXITSTATUS(status),
                child);
    }

    printf("Parent[pid=%d]: exiting\n", mypid);

    exit(0);

} /* main */

以及一个执行的一个示例:

$ a.out
Parent[pid=81452]: I have started child (pid = 81453)
Parent[pid=81452]: I have started child (pid = 81454)
Parent[pid=81452]: I have started child (pid = 81455)
Parent[pid=81452]: I have started child (pid = 81456)
Child [pid=81453]: start
Child [pid=81453]: wait for 34 secs.
Child [pid=81455]: start
Child [pid=81455]: wait for 56 secs.
Child [pid=81456]: start
Child [pid=81456]: wait for 42 secs.
Parent[pid=81452]: I have started child (pid = 81457)
Parent[pid=81452]: I have started child (pid = 81458)
Parent[pid=81452]: I have started child (pid = 81459)
Parent [pid=81452]: sleeping for 30s.
Child [pid=81454]: start
Child [pid=81454]: wait for 9 secs.
Child [pid=81457]: start
Child [pid=81457]: wait for 58 secs.
Child [pid=81458]: start
Child [pid=81458]: wait for 30 secs.
Child [pid=81459]: start
Child [pid=81459]: wait for 14 secs.
Child [pid=81454]: exiting with code=9
Child [pid=81459]: exiting with code=14
Child [pid=81458]: exiting with code=30
Parent [pid=81452]: beginning to wait.   <<<<< before this message, you can see Zombie processes.
Parent[pid=81452]: detected exit(14) from child(pid=81459)
Parent[pid=81452]: detected exit(30) from child(pid=81458)
Parent[pid=81452]: detected exit(9) from child(pid=81454)
Child [pid=81453]: exiting with code=34
Parent[pid=81452]: detected exit(34) from child(pid=81453)
Child [pid=81456]: exiting with code=42
Parent[pid=81452]: detected exit(42) from child(pid=81456)
Child [pid=81455]: exiting with code=56
Parent[pid=81452]: detected exit(56) from child(pid=81455)
Child [pid=81457]: exiting with code=58
Parent[pid=81452]: detected exit(58) from child(pid=81457)
Parent[pid=81452]: exiting
$ _

相关问题