Mehrere Kindprozesse unter Linux erzeugen und verwalten



  • Hi,
    ich schreibe im Moment an einer Simulation. Diese wird in einem Prozess ausgeführt und es können mehrere solche Prozesse mit verschiedenen Parametern parallel laufen.

    Ich erzeuge mir hier vier Kindprozesse mit fork und überschreibe diese mit execl. Soweit geht alles. Nun möchte ich aber eine Rückmeldung der einzelnen Prozesse haben. Wenn also ein Prozess zu Ende ist, möchte ich das im Elternprozess wissen. Ich dachte da an waitpid(). Mir ist nur noch nicht klar, wie ich das realisiere.
    Ich jetztigen Code warte ich alle Kindprozesse mit wait ab. Was für einen Status bekomme ich da eigentlich? Das ist nur der Status des ersten Kind Prozesses oder?

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    main(void)
    {
        int Num_Proc= 4;
        pid_t pid1 = 1;
    
        int status1;
        int PID[2];
        int i;
    
        pid1 = fork();
    
        if (pid1 == 0)
        {
            for(i=0;i<(Num_Proc/2);i++)
            {
                fork();
            }
            printf("Ich bin der Kindprozess.\n");
    
            execl("/home/tom/Projects/simulation", "simulation", NULL);
    
            perror("In exec(): ");
    
        }
    
        if (pid1 > 0)
        {
            printf("Ich bin der Elternprozess, das Kind ist %d.\n",
    
                   pid1);
    
            pid1 = wait(&status1);
            printf("Ende des Prozesses %d: ", pid1);
        }
    
        if (pid1 < 0)
        {
    
            perror("In fork():");
    
        }
    
        exit(0);
    

    }

    Hoffentlich ist das nicht zu speziell. Ich freu mich auf jeden Fall über jede Antwort.

    Mfg Mo3bius



  • Du musst dir die PID aller erzeugten Prozesse merken, wenn du auf alle Prozesse warten moechtest.



  • Naja und genau da häng ich im Moment. 😉

    Ich kann ja in der if-Schlife(if(pid1 == 0)) nach den Forkanweisungen mir mit getpid() den pid-Wert ausgeben. Diesen muss ich aber doch irgendwie an den Elternprozess weitergeben?

    Vielleicht geht das ganz einfach, ich habe das nur noch nie gemacht.

    Mfg Mo3bius



  • Dein Code beinhaltet schon den richtigen Ansatz zum Speichern der PID.
    Hier noch mal ein kleiner Ausschnitt aus den manpages zu fork():

    RETURN VALUE
    On success, the PID of the child process is returned in the parent, and
    0 is returned in the child. On failure, -1 is returned in the parent,
    no child process is created, and errno is set appropriately.

    Das Abspeichern der PID muss im Fall if(PID > 0) passieren. Damit muss dieser Fall auch in die Schleife in der fork() verwendet wird vorkommen.
    In Pseudocode sieht das ungefähr so aus.

    for i is 0 to 3{
       pid = fork()
       if pid > 0{
          /* speichere PID */
       }else if pid == 0{
          /* Code des Kindprozesses i*/
          return
       }else{
          /* Error */
    }
    for i is 0 to 3{
       /* hole PID von Kindprozess i */
       /* warte auf Kindprozess i*/
    }
    


  • @cookiness:

    Die PID wird beim forken an den Elternprozess weitergegeben. Bei meinem Ansatz geht das aber nicht so einfach. Ich habe erst 1 Kind erzeugt und dieses dann immer wieder geforkt. Somit sehe ich das im ersten Elternprozess nicht mehr.

    Um das Problem zu umgehen habe ich für jedes Kind/Enkelkind.. eine Pipe zum Masterprozess gelegt und habe damit die PID übertragen.

    Das hat auch funktioniert. Dummerweise funktioniert waitpid() nur richtig mit Kindern und nicht Enkelkindern. Somit kann ich nur auf alle Prozesse warten was mir nicht reicht.

    Ich habe das Ganze überarbeitet und forke nun immer vom ersten Prozess. Damit geht alles. 😃

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    main(void)
    {
        int Num_Proc= 2;
    
        int i,forki;
    
        int * active=(int *)malloc((unsigned) (Num_Proc)*sizeof(int));
        int * status=(int *)malloc((unsigned) (Num_Proc)*sizeof(int));
        int * timer=(int *)malloc((unsigned) (Num_Proc)*sizeof(int));
        pid_t * pid=(pid_t *)malloc((unsigned) (Num_Proc)*sizeof(pid_t));
        int goon = 1;
        pid_t pidmaster;
        int status1;   
    
        for(forki=0;forki<Num_Proc;forki++)
        {
            pidmaster = fork();
    
            if (pidmaster == 0)
            {
                printf("Ich bin der Kindprozess %d.\n",getpid());
                execl("/home/tom/Projects/simulation", "simulation", NULL);
                exit(1);
            }
            else if(pidmaster > 0)
            {
                pid[forki] = pidmaster;
            }
            else
            {
                //error;
            }
    
        }
    
        i = 0;
    
        while (goon != 0)
        {
            goon = 0;
            for(i=0;i<Num_Proc;i++)
            {
                if((status1 = waitpid(pid[i], &status[i], WNOHANG)) >= 0)
                {
                    active[i] = 1;
                    timer[i] +=Num_Proc;    //Wait 1 sec after each process.
                }
                else
                {
                    active[i] = 0;
                    timer[i] = 0;
                    printf("Ende des Prozesses: %d, Status: %d %d\n", pid[i],status1,status[i]);
                }
                sleep(1);
            }
    
            for(i=0;i<Num_Proc;i++)
            {
                goon += active[i];
            }
        }
    
        exit(0);
    
    }
    


  • wielange brauchen deine Simulationen momentan? Ich denke bei Laufzeiten über 4 Milli-Sekunden gibts Probleme, weil du 0 active zählst^^

    Vielleicht macht das das auffäumen leichter:

    int stillAlive = 4;
    while (stillAlive > 0) {
        waitpid(-1, &status, WNOHANG);
        stillAlive++;
        sleep(1);
    }
    

    oder gleich 4 mal waitpid(-1, &status, 0); ?
    Hängt auch ein bischen von deiner restlichen Anwendung ab. 😋



  • http://linux.die.net/man/2/waitpid

    waitpid(): on success, returns the process ID of the child whose state has changed; on error, -1 is returned; if WNOHANG was specified and no child(ren) specified by pid has yet changed state, then 0 is returned.

    Das gleiche gilt für deinen anderen Beitrag in diesem Forum. Dort sollte auch >= 0 stehen. 😉

    Mfg Mo3bius



  • ok danke für den Tipp,
    aber:
    pid = -1 heißt Fehler
    pid = 0 heißt Kein Beendeter Prozess -> active hochzählen
    pid > 0 heißt Prozess aufgeräumt -> active nicht hochzählen

    und im anderen Thread sollte ja bei keiner Änderung auch nichts gemacht werden.

    Also: pid > 0 -> einer weniger, pid = 0 -> keine Änderung -> nichts machen
    Oder übersehe ich gerade irgendwas wichtiges *leicht verwirrt*?



  • @DerBaer:

    ich bin mir nicht sicher ob ich dir folgen kann. Ich kann ja mal schreiben wie ich das seh.
    Wenn WNOHANG angegeben wird, dann gibt waitpid 0 aus, wenn der Prozess läuft. Sobald der Prozess beendet wird gibt waitpid immer -1 aus.

    Waitpid (mit WNOHANG) wird sofort ausgeführt. Es wird also die nächste Anweisung angegangen. Ich habe nun über waitpid eine while-Schleife gelegt und frage ab, ob die SUmme aller noch laufenden Prozesse (also wo waitpid 0 ausgibt) > 0 ist. Ist dem so, so läuft mindestens noch ein Prozess.
    Wenn

    waitpid(pid,&status,WNOHANG)
    

    -1 ausgibt, kann ich den Wert von status überprüfen. Dieser gibt dann an unter welchen Umständen der Prozess beednet wurde.

    Mfg Mo3bius



  • Mo3bius schrieb:

    Wenn WNOHANG angegeben wird, dann gibt waitpid 0 aus, wenn der Prozess läuft. Sobald der Prozess beendet wird gibt waitpid immer -1 aus.

    waitpid gibt -1 beim Fehler aus(sollte nie passieren), und die pid, wenn der Prozess beendet wird. 0 wenn es keinen beendeten gefunden hat.

    Mo3bius schrieb:

    Waitpid (mit WNOHANG) wird sofort ausgeführt. Es wird also die nächste Anweisung angegangen. Ich habe nun über waitpid eine while-Schleife gelegt und frage ab, ob die SUmme aller noch laufenden Prozesse (also wo waitpid 0 ausgibt) > 0 ist. Ist dem so, so läuft mindestens noch ein Prozess.

    Ja, waitpid mit WNOHANG kehrt sofort zurück, sodass weitergerechnet werden kann. Aber wenn waitpid = 0 zurückgibt, heißt das nur, dass es keinen Prozess mit geändertem Status (meistens dann beendet 🙂 ) gefunden hat. Das heißt aber noch lange nicht, dass es noch Prozesse gibt.


Anmelden zum Antworten