Prozesse unter Linux   beim Start von UNIX ist nur ein Prozess aktiv (init-Prozess)

Wie werden neue Prozesse erzeugt?

jeder neue Prozess benötigt BM und Identifikator; dazu ist die Hilfe des Betriebssystem notwendig

fork

        Erzeugt einen neuen Prozess.

        Dieser besitzt einen eigenen Adressraum.

        Er ist eine exakte Kopie (gesamter Zustand W×Addr) des Vaterprozesses, besitzt jedoch einen eigenen PID.

        „Copy on Write“-Prinzip

        Beide Prozesse existieren nach dem fork()-Ruf parallel und sind dem Scheduling unterworfen.

        Es ist nicht determiniert, welcher zuerst fortgesetzt wird.

        Erzeugender Prozess (Vater) ruft fork()

        Betriebssystem erstellt identische Kopie des Vaters (Code, Daten, Stack)

        fork()-Ruf kehrt zweimal zurück, einmal im Sohn und einmal im Vater, beide Male jedoch an dieselbe Stelle.

        Erzeugter Prozess (Sohn) erhält vom Betriebssystem eindeutigen Identifikator, (inclusive Anlegen aller Verwaltungsinformationen)

        bestimmte BM erbt der Sohn vom Vater (Dateihandles, Umgebungsvariable, Arbeitsverzeichnis)

        andere BM (z. B. Hauptspeicher) teilt ihm das BS zu, Vater erhält als Rückgabewert die PID des Sohnes.

        Sohn erhält 0 als Rückgabewert.

        Bei einem Fehler liefer fork() -1 zurück; (Speicher voll, maximale Prozesszahl erreicht…)

        fork() erzeugt nur identische Prozesse.

1        #include <stdio.h>

2        #include <sys/types.h>

3        #include <unistd.h>

4        int main(void)

5        {

6                pid_t pid;

7                       

8                if((pid = fork()) < 0)

9                         {       

10                              printf("fork failed!\n");

11                               exit(1);

12                        }

13               if(pid == 0) printf("Sohn, pid=%d\n",getpid());

14               else printf("Vater-pid=%d, Sohn-pid=%d\n",getpid(), pid)

15              return 0;

16        }

exec

        Erfolgt innerhalb eines Prozesses ein exec()-Ruf, dann wird der ursprüngliche Code durch einen neuen überschrieben und mit dessen Abarbeitung begonnen.

        Argumente sind Pfadangaben des zu ladenden Programms sowie dessen Kommandozeilenparameter.

        Ist exec()-Ruf erfolgreich, dann kehrt dieser nicht zurück, bei einem Fehler liefert dieser eine –1 zurück.

        Es existieren 6 verschiedene exec()-Rufe.

exit  Beendet den rufenden Prozess.

#include <stdio.h>

#include <sys/types.h>

#include <unistd.h>

int main(void)

{

    pid_t pid;

    if ((pid = fork()) < 0)

        {

            printf("fork failed!\n");

            exit(1);

        }

    if (pid = = 0)

        {

            printf("Sohn, pid=%d\n",getpid());

            execl("/bin/ls","ls","-al",NULL);

        }

            else printf("Vater-pid=%d, Sohn-pid=%d\n",getpid(), pid);

            return 0;

}

wait waitpid

        Unterbrechung des (rufenden) Vaterprozesses und Warten, dass irgendein bzw. ein bestimmter Kindprozess terminiert.

        Beide Rufe liefern PID des Sohnes zurück oder –1 bei Fehler.

        Beim nachfolgenden Beispiel wird, egal wer zuerst aus dem fork()-Ruf zurückkehrt, erzwungen, das der Sohn vor dem Vater terminiert.

#include <stdio.h>

#include <sys/types.h>

#include <unistd.h>

int main(void)

{

    pid_t pid;

    if((pid = fork()) < 0)

        {

            printf("fork failed!\n");

            exit(1); }

            wait();

                if(pid==0)

                    {

                        printf("Sohn, pid=%d\n",getpid());

                         execl("/bin/ls","ls","-al",NULL);

                    }  else

                    printf("Vater, pid=%d, pid des Sohnes=%d\n",getpid(), pid);

                    return 0;

         }

Es gibt drei Möglichkeiten, wie sich ein Prozess beenden kann:

1) normales Verlassen des main-Blocks

2) return im main-Block rufen

3) exit()-Systemruf irgendwo im Programmcode.

2) und 3) ermöglichen es, einen Rückgabewert an den Vater weiterzureichen.

Wenn sich ein Prozess beendet, sollten seine Ressourcen freigegeben werden.

Wie kann ein Rückgabewert aufbewahrt werden, wenn alle Ressourcen des Prozesses bereits freigegeben wurden?

gar nicht

        Es wird der „Zombie“-Zustand eingeführt

        Es handelt sich um einen Übergangszustand vor „nicht existent“, von dem aus der Prozess nur noch nach „nicht existent“ übergehen kann. (das nennt man transient und irreversibel)

        In diesem Zustand werden nur noch Verwaltungsinformation und Rückgabewert aufbewahrt.

        Diese erhält der Vater, wenn er wait() ruft.

        Danach geht der Prozess in „nicht existent“ über, und die Infos werden freigegeben.

Gegeben sei der nachfolgende Code eines Prozesses A, der zum Zeitpunkt gestartet wird. Welche Prozesse existieren zu den Zeitpunkten t={10s,30s,...,110s} im System und welche „Verwandtschaftsbeziehungen“ bestehen zwischen ihnen.

#include <sys/types.h>

void main(void)

{

   sleep(20);

    fork(); /* 1. fork()-Ruf */

    sleep(20);

    fork(); /* 2. fork()-Ruf */

    wait(NULL);

    sleep(20);

    fork(); /* 3. fork()-Ruf */

    sleep(20);

}

 

Wie viele Prozesse in dem folgendem Programm entstehen neu?

#include <sys/types.h>

int  main(void) 
{   int i = 2;
    pid_t pid;
	while (i>0)
    {	if(i==2) {pid = fork();
	           sleep(3);
		   printf("\n");
		   if (pid==0) printf("Sohn1, pid=%d\n", getpid());
		   else printf("Vater1-pid=%d Sohn_pid=%d\n", getpid(),pid);}
    	if(i==1)  {pid = fork();
		   sleep(3);
		   printf("\n");
		   if (pid==0) printf("Sohn2, pid=%d\n", getpid());
		   else printf("Vater2-pid=%d Sohn_pid=%d\n", getpid(),pid);
		   wait();}
        if(i==0) { pid = fork();
		   sleep(3);
		   printf("\n");
		   if (pid==0) printf("Sohn3, pid=%d\n", getpid());
		   else printf("Vater3-pid=%d Sohn_pid=%d\n", getpid(),pid);
		   wait();}
        i--; 
   }
}

Ausgabe Bildschirm:
Antwort : 3 neue Prozesse, insgesamt 4 Prozesse ("fork_3")im System.
 

Für das Betriebssystem UNIX sei folgender Ausschnitt eines Programmcodes gegeben:

...

fork(); // 1.fork

fork(); // 2.fork

fork(); // 3.fork

...

Gib in einer Skizze an, welche Prozesse durch welches fork erzeugt werden!

Der Prozess, der mit dem obigen Programmcode läuft, hat den PID=0x20a. Der Prozessmanager erzeugt für jeden neuen Prozess den PID durch inkrementieren um 1 des letzten vergebenen. Gib die PIDs der neuen Prozesse an, wenn sonst keine weitere Prozesserzeugung gefordert wird! Ist das überhaupt determiniert möglich?

Diese PID-Zuordnung ist determiniert nicht möglich, da die Prozesse  entsprechend dem Scheduler bearbeitet werden, d.h. es wird immer der nächste Prozess aktiv. Je nachdem welcher Prozess gerade beim fork() aktiv ist, bekommt dessen Sohn die nächste PID.

Für die Betriebssystem-Schnittstelle Win32 (u.a. Win2K/WinXP) sei folgender Ausschnitt eines Programmcodes gegeben

aa.exe:

...

CreateProcess(bb.exe, ...);

CreateProcess(cc.exe, ...);

CreateProcess(dd.exe, ...);

...

Gib in einer Skizze an, welche Prozesse durch welches CreateProcess(...) erzeugt werden!

Der Prozess, der mit dem obigen Programmcode läuft, hat die ProcessId=0x20a. Der Prozessmanager erzeugt für jeden neuen Prozess die Process-Id durch inkrementieren um 1 es letzten vergebenen. Gib die Process-Ids der neuen Prozesse an, wenn sonst keine weitere Prozesserzeugung gefordert wird! Ist das überhaupt determiniert möglich?

Es ist eine determinierte Zuordnung möglich, da mit jedem CreateProcess  immer genau ein neuer Prozess erzeugt wird.