UNIX Commands

ps Command um Prozesse zu sehen

  • Prozesszustand

    R - läuft auf einem Prozessor (running)

    S – vorübergehend schlafend (< 20 s), z. B. durch Aufrufe wie sleep()

    I – inaktiv, schlafend (≥ 20 s)

    D – ununterbrechbar schlafend, meist wegen I/O

    T – angehalten oder getraced (stopped or traced)

    W – ausgelagert (swapped)

    Z – Zombie (zombie)

Was ist der Unterschied zwischen fork( ) und execve( )?

fork() erstellt einen Kindprozess, das heißt wir haben anschließend zwei Prozesse, diese beiden können weiter laufen, welcher P. wann arbeitet kann mittels Semaphoren gesteuert werden. execve() hingegen erzeugt einen neuen Prozess, der den jetztigen überschreibt, der ‘’alte” Code läuft nicht mehr.

int execve(const char *filename, char *const argv [], char *const envp[]);
  • filename contains the path to the new program

  • argv are the command line arguments for the new process

  • envp is a string array of environment strings

  • The argv and envp arrays are terminated by the NULL pointer.

Process Creation 🎨

Welche Eigenschaften hat ein Child Process ?

After using fork( ) a child process is created. It inherits many things from the parent process.

  • Unique PID

  • CPU time set to 0

  • PPID : parent Process ID

  • Inherits file descriptors, priority, etc.

  • does not inherit file locks

Return Codes von fork()

RückgabewertBedeutungTypische Aktion
0Im Kindprozesschild_code();
PID des KindesIm Elternprozessparent_code();
-1Fehlererror_handling();
switch (fork()) {
case 0:     child_code();      break; // Kindprozess
case -1:    error_handling();  break; // Fehler
default:    parent_code();     break; // Elternprozess
}

Waiting for Completion ⏰

Important

Mittels wait() oder waitpid() kann ein Elternprozess warten, biss ein Kinprozess aufgehört hat zu arbeiten.

pid t wait(int *status);
pid t waitpid(pid t wpid, int *status, int options);

Was sind Zombie - Prozesse ?

Zombie Prozesse sind bekannt als :
Ein Eltern-Prozess wartet normalerweise auf die Completion von dem Kindprozess (status code). Wenn allerdings ein LKindprozess läuft, und kein Elternprozess auf diesen wartet → Zombieprozess

Auf welche Ereignisse kann man warten ?

  • DEFAULT : prozess terminiert

  • WUNTRACED → Rückkehr auch, wenn der Kindprozess gestoppt wird (Signale): SIGTTIN, SIGTTOU, SIGTSTP, SIGSTOP

  • WCONTINUED → Rückkehr auch, wenn ein gestoppter Kindprozess _fortgesetzt_wird (SIGCONT).

  • WNOHANG → Sofort zurückkehren, auch wenn noch kein Kindprozess beendet wurde (nützlich für nicht-blockierendes Warten).

Aus was stellt sich ein Status zusammen ?

  • EXIT CODE des Kindes (falls normal beendet)

  • SIGNAL, falls der Prozess durch ein Signal beendet wurde

Wie kann man einen Exit Status / Signal herauslesen ?

Mittels WEXITSTATUS() or WTERMSIG().

Die 5 Variationen von execve()

FunktionSearch Path (PATH)?ArgumentformatEnvironment-Übergabe möglich?
execl❌ (Pfad muss voll angegeben werden)Liste von Strings (...)
execlp✅ (Sucht in PATH)Liste von Strings (...)
execleListe von Strings (...) + letztes Argument ist envp[]
execvArray argv[]
execvpArray argv[]

Was sind die grundsätzlichen Unterschiede zwischen den Varianten ?

  1. PATH - PATH setzen oder nicht

  2. Format von argv – ob die Argumente als variadische Parameter (...) oder als Array (argv[]) übergeben werden.

  3. Environment – ob du ein eigenes Environment setzen kannst.

Important

Ein Environment beinhaltet eine semi-permanente Konfiguration für Programme

Beispiel Konfigurationen des Environments :

  • PATH – the program search path

  • TERM – the kind of terminal

  • PRINTER – the user’s default printer

  • ==Environment== = Satz an Key-Value-Paaren, die ein Prozess von seiner Shell/Elternprozess erbt.

  • Beispiele:

    • PATH → Suchpfad für Programme

    • TERM → Terminal-Typ

    • PRINTER → Standarddrucker

Beispiele von Umgebungsvariablen 🌳

$ TESTVAR=abc
$ echo $TESTVAR
abc                # Variable ist in der aktuellen Shell gesetzt
 
$ ./getenv TESTVAR
TESTVAR is not set # Kindprozess (Programm) sieht die Variable nicht,
                   # da sie nicht exportiert wurde
 
$ export TESTVAR
$ ./getenv TESTVAR
TESTVAR=abc        # Jetzt im Environment verfügbar
 
$ TESTVAR=
$ ./getenv TESTVAR
TESTVAR=           # Variable ist leer, aber vorhanden
 
$ unset TESTVAR
$ ./getenv TESTVAR
TESTVAR is not set # Variable komplett gelöscht

PROCESS RESOURCE USAGE — SKIP

Solution : Semaphores 🛠️

Semaphoren sind IPC Mechanisamen - Inter Process Communication

When are Semaphores needed ?

Wir brauchen Semaphoren wenn mehrere Prozesse eine gemeinsame Ressource benutzen. Sie koordinieren den Zugriff auf kritische Abschnitte.

Was ist das Shared Memory Problem ?

Angenommen zwei Prozesse greifen auf diesselbe Speicheradresse 0x10000000 zu. Bei 0x10000000 steht der Wert 0.
P1 schreibt an dieser Stelle den Wert 42 rein. Jetzt ließt P2 den Wert bei 0x10000000 . Wird dieser 0 oder 19 sein ?

Important

Ohne eine bestimmte Reihenfolge der Abarbeitung / Plan könnte passieren :

  • P1 wird gestoppt

  • P2 wird gestoppt

  • Vielleicht läuft einer auf einer kleineren Priorität ?

  • Vielleicht gab es ein IO Problem ?

Was ist P() bei einem Semaphor ?

P steht für passeren und bedeutet ==“Ich möchte diese Ressource nutzen”==

Cases :

  1. Falls der Wert des Semaphors == 0 ist → Warten

  2. Falls der Wert des Semaphors >= 1 → Fortfahren, Wert um 1 ==dekrementieren==.

Was ist V() bei einem Semaphor ?

V steht für vrijgeven und bedeutet ==“Ich bin fertig und gebe die Ressource frei !”==

Cases :

  1. Prozess gibt Ressourcen frei

  2. Semaphor Wert wird um 1 erhöht

Important

Mittels semget() kann man ein Semaphoren Paar anfordern.

Die Operationen auf einem S-Paar werden mit semop() durchgeführt.

Ein Semaphoren Paar lässt sich mit semctl() entfernen.

C Code Semaphor Beispiel

Create new Semaphore Set

/* create new semaphore set with n semaphores, return semid */
int new_sem(int n)
{
return semget(IPC_PRIVATE, n, SEM_A | SEM_R );
}

Operation on Semaphore Sets

int operation_p(int semid) /* enter critical region */
{
struct sembuf sb;
sb.sem_num = 0;
sb.sem_flg = 0;
sb.sem_op = -1;
if (semop(semid, &sb, 1) < 0) /* 1 operation */
{
perror("semop() in operation_p()");
return 0; /* false, error */
}
return 1; /* true, success */
}

Delete Semaphore Set

/* delete semaphore set semid */
int delete_sem(int semid)
{
if (semctl(semid, 0, IPC_RMID) < 0)
{
perror("semctl(sem, 0, IPC_RMID, 0)");
return 0; /* error removing semaphore */
}
return 1; /* success */
}

UNIX : Shared Memory Segment

SchrittFunktionZweck
1shmget()Shared-Memory-Segment anlegen (gibt Segment-ID zurück)
2shmat()Segment in den Adressraum einbinden (Pointer erhalten)
3Pointer nutzenLese-/Schreiboperationen im Shared Memory
4shmctl()Segment löschen oder Attribute ändern

image 27.png

image 1 9.png