GNU/Linux >> Znalost Linux >  >> Linux

Linuxové procesy – ID procesů, funkce fork, execv, wait, waitpid C

V tomto článku začneme malým vysvětlením ID procesů a poté rychle přejdeme k praktickým aspektům, kde probereme některé funkce jazyka C související s procesy, jako je fork(), execv() a wait() .

Linux Processes Series:část 1, část 2, část 3 (tento článek).

ID procesů

ID procesů jsou identifikátory procesů, které jsou nezáporná čísla spojená s procesem. Tato čísla jsou jedinečná v rámci procesů běžících v systému.

Tuto jedinečnost ID procesu proces někdy používá k vytvoření některých jedinečných názvů souborů. Když je proces ze systému ukončen, jeho ID procesu je zpřístupněno pro opětovné použití.

Existuje však určitá prodleva, která se počítá před zpřístupněním ID procesu pro opětovné použití. Je to proto, že ID procesu, které bylo spojeno s předchozím procesem, který je nyní ukončen, může být dobře použito ve formě názvu souboru atd. Před opětovným použitím stejného ID procesu je tedy přidáno zpoždění.

ID procesu 1 je pro proces init. Toto je první proces, který se spustí po spuštění systému.

Programový soubor pro proces init lze nalézt buď v /etc/init nebo v /sbin/init. Proces init je proces na úrovni uživatele, ale běží s právy root a je zodpovědný za uvedení systému do stavu, jakmile se jádro zavede. Spouštěcí soubory načtené procesem init k dosažení určitého stavu jsou

  • /etc/rc*.d
  • /etc/init.d
  • /etc/inittab

ID procesu 0 je plánovačem systému. Je to proces na úrovni jádra zodpovědný za veškeré plánování procesů, které se odehrává uvnitř systému.

Funkce řízení procesu

Funkce fork()

Jak již bylo uvedeno v článku o vytvoření procesu démona v C, fork Funkce se používá k vytvoření procesu zevnitř procesu.

Výsledný nový proces vytvořený fork() je známý jako podřízený proces, zatímco původní proces (ze kterého byla fork() volána) se stává rodičovským procesem.

Funkce fork() je volána jednou (v rodičovském procesu), ale vrací se dvakrát. Jednou se vrátí v nadřazeném procesu, zatímco podruhé se vrátí v podřízeném procesu. Všimněte si, že pořadí provádění nadřazeného a podřízeného prvku se může lišit v závislosti na algoritmu plánování procesu. Vidíme tedy, že funkce vidlice se používá při vytváření procesu .

Podpis fork() je  :

pid_t fork(void);

Skupina funkcí exec

Další sadou funkcí, které se obecně používají pro vytváření procesu, je exec rodina funkcí. Tyto funkce se používají hlavně tam, kde je potřeba spustit existující binární soubor z procesu.

Předpokládejme například, že chceme spustit příkaz „whoami“ z procesu, pak se v těchto typech scénářů použije funkce exec() nebo další členové této rodiny. Zde stojí za zmínku, že při volání kterékoli z funkcí skupiny exec je aktuální obraz procesu nahrazen obrazem nového procesu.

Společným členem této rodiny je funkce execv(). Jeho podpis je :

int execv(const char *path, char *const argv[]);

Poznámka :Podívejte se prosím na manuálovou stránku exec a podívejte se na ostatní členy této rodiny.

Funkce wait() a waitpid()

Existují určité situace, kdy když podřízený proces skončí nebo změní stav, měl by se nadřazený proces dozvědět o změně stavu nebo stavu ukončení podřízeného procesu. V takovém případě funguje jako wait() jsou používány nadřazeným procesem, kde se nadřazený může pomocí těchto funkcí dotazovat na změnu stavu podřízeného procesu.

Podpis funkce wait() je  :

pid_t wait(int *status);

Pro případy, kdy má nadřazený proces více než jeden podřízený proces, existuje funkce waitpid() které může rodičovský proces použít k dotazu na stav změny konkrétního potomka.

Podpis waitpid() je :

pid_t waitpid(pid_t pid, int *status, int options);

Ve výchozím nastavení čeká  waitpid() pouze na ukončené potomky, ale toto chování lze upravit pomocí argumentu options, jak je popsáno níže.

Hodnota pid může být:

  • <-1 :Počkejte na jakýkoli podřízený proces, jehož ID skupiny procesů se rovná absolutní hodnotě pid.
  • -1 :Počkejte na jakýkoli podřízený proces.
  • 0 :Počkejte na jakýkoli podřízený proces, jehož ID skupiny procesů je stejné jako ID volajícího procesu.
  • > 0 :Počkejte na potomka, jehož ID procesu se rovná hodnotě pid.

Hodnota voleb je OR nula nebo více následujících konstant:

  • WNOHANG:Pokud žádné dítě neodejde, okamžitě se vraťte.
  • WUNTRACED :Vraťte se také, pokud dítě přestalo. Stav pro sledované děti, které se zastavily, je poskytován i v případě, že tato možnost není zadána.
  • WCONTINUED :Vraťte se také, pokud bylo zastavené dítě obnoveno doručením SIGCONT.

Pro více informací o waitpid() se podívejte na manuálovou stránku této funkce.

Příklad programu

Zde máme příklad, kde jsme použili všechny typy funkcí popsaných výše.

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

int global; /* In BSS segement, will automatically be assigned '0'*/

int main()
{
    pid_t child_pid;
    int status;
    int local = 0;
    /* now create new process */
    child_pid = fork();

    if (child_pid >= 0) /* fork succeeded */
    {
        if (child_pid == 0) /* fork() returns 0 for the child process */
        {
            printf("child process!\n");

            // Increment the local and global variables
            local++;
            global++;

            printf("child PID =  %d, parent pid = %d\n", getpid(), getppid());
            printf("\n child's local = %d, child's global = %d\n",local,global);

            char *cmd[] = {"whoami",(char*)0};
            return execv("/usr/bin/",cmd); // call whoami command

         }
         else /* parent process */
         {
             printf("parent process!\n");
             printf("parent PID =  %d, child pid = %d\n", getpid(), child_pid);
             wait(&status); /* wait for child to exit, and store child's exit status */
             printf("Child exit code: %d\n", WEXITSTATUS(status));

             //The change in local and global variable in child process should not reflect here in parent process.
             printf("\n Parent'z local = %d, parent's  global = %d\n",local,global);

             printf("Parent says bye!\n");
             exit(0);  /* parent exits */
         }
    }
    else /* failure */
    {
        perror("fork");
        exit(0);
    }
}

Ve výše uvedeném kódu jsem se pokusil vytvořit program, který:

  • Používá fork() API k vytvoření podřízeného procesu
  • Používá lokální a globální proměnnou k prokázání toho, že fork vytváří kopii nadřazeného procesu a podřízený má svou vlastní kopii proměnných, se kterou může pracovat.
  • K volání příkazu „whoami“ používá execv API.
  • Používá wait() API k získání stavu ukončení podřízeného v nadřazeném objektu. Všimněte si, že toto rozhraní API zadržuje provádění nadřazeného prvku, dokud podřízený objekt neukončí nebo nezmění jeho stav.

Nyní, když je výše uvedený program spuštěn, vytváří následující výstup:

$ ./fork
parent process!
parent PID =  3184, child pid = 3185
child process!
child PID =  3185, parent pid = 3184

child's local = 1, child's global = 1
himanshu
Child exit code: 0

Parent'z local = 0, parent's  global = 0
Parent says bye!

Linux
  1. 30 Cvičení procesů Linuxu pro systémové správce

  2. Linux – Init Process:Předchůdce všech procesů?

  3. UNIX / Linux Procesy:C fork() Funkce

  1. Správa procesů v Ubuntu Linux

  2. Jak najít všechny podřízené procesy?

  3. Opakování vidlice bash ssh Linuxu:žádné podřízené procesy

  1. Linux:Najděte a zabijte zombie procesy

  2. Jak vypočítat využití CPU procesu a všech jeho podřízených procesů v Linuxu?

  3. Ztráta času execv() a fork()