GNU/Linux >> Linux Esercitazione >  >> Linux

Impara e usa le chiamate di sistema fork(), vfork(), wait() ed exec() su sistemi Linux

Si è riscontrato che in qualsiasi sistema operativo basato su Linux/Unix è bene capire fork e vfork chiamate di sistema, come si comportano, come possiamo usarle e le differenze tra loro. Insieme a questi aspetta e esecutivo le chiamate di sistema vengono utilizzate per la generazione dei processi e varie altre attività correlate.

La maggior parte di questi concetti viene spiegata utilizzando esempi di programmazione. In questo articolo tratterò cosa sono le chiamate di sistema fork, vfork, exec e wait, i loro caratteri distintivi e come possono essere utilizzati al meglio.

fork()

fork(): Chiamata di sistema per creare un processo figlio.

[email protected] ~}$ man fork

Ciò produrrà un output che menziona a cosa serve il fork, la sintassi e tutti i dettagli richiesti.

La sintassi utilizzata per la chiamata di sistema fork è la seguente,

pid_t fork(void);

La chiamata di sistema fork crea un figlio che differisce dal processo padre solo in pid(ID processo) e ppid(ID processo padre) . L'utilizzo delle risorse è impostato su zero. I blocchi di file e i segnali in sospeso non vengono ereditati. (In Linux "fork" è implementato come "copy-on-write() “).

Nota:- "Copia in scrittura ” -> Ogni volta che viene chiamata una chiamata di sistema fork(), una copia di tutte le pagine (memoria) relative al processo padre viene creata e caricata in una posizione di memoria separata dal sistema operativo per il processo figlio. Ma questo non è necessario in tutti i casi e potrebbe essere richiesto solo quando un processo scrive in questo spazio di indirizzi o area di memoria, quindi viene creata/fornita solo una copia separata.

Valori di ritorno :-  PID (ID processo) del processo figlio viene restituito nel thread di esecuzione dei genitori e "zero ” viene restituito nel thread di esecuzione del figlio. Di seguito è riportato l'esempio di programmazione c che spiega come funziona la chiamata di sistema fork.

[email protected] ~}$ vim 1_fork.c
#include<stdio.h>
#include<unistd.h>
Int main(void)
{
printf("Before fork\n");
fork();
printf("after fork\n");
}
[email protected] ~}$ 
[email protected] ~}$ cc 1_fork.c
[email protected] ~}$ ./a.out
Before fork
After fork
[email protected] ~}$

Ogni volta che viene effettuata una chiamata di sistema, ci sono molte cose che accadono dietro le quinte in qualsiasi macchina unix/linux.

Prima di tutto il cambio di contesto avviene dalla modalità utente alla modalità kernel (sistema). Questo si basa sulla priorità del processo e sul sistema operativo unix/linux che stiamo utilizzando. Nel codice di esempio C sopra, stiamo usando "{" parentesi graffa aperta che è l'ingresso del contesto e "}" parentesi graffa chiusa è per uscire dal contesto. La tabella seguente spiega molto chiaramente il cambio di contesto.

vfork()

vfork –> crea un processo figlio e blocca il processo padre.

Nota:- In vfork, i gestori dei segnali vengono ereditati ma non condivisi.

[email protected] ~}$ man vfork

Ciò produrrà un output che menziona per cosa viene utilizzato vfork, la sintassi e tutti i dettagli richiesti.

pid_t vfork(void);

vfork è uguale a fork tranne per il fatto che il comportamento non è definito se il processo creato da vfork modifica qualsiasi dato diverso da una variabile di tipo pid_t utilizzata per memorizzare il valore restituito p di vfork o chiama qualsiasi altra funzione tra la chiamata di _exit() o uno degli exec () famiglia.

Nota: vfork è talvolta indicato come caso speciale di clone.

Di seguito è riportato l'esempio di programmazione C per vfork() come funziona.

[email protected] ~}$ vim 1.vfork.c
#include<stdio.h>
#include<unistd.h>
Int main(void)
{
printf("Before fork\n");
vfork();
printf("after fork\n");
}
[email protected] ~}$ vim 1.vfork.c
[email protected] ~}$ cc 1.vfork.c
[email protected] ~}$ ./a.out
Before vfork
after vfork
after vfork
a.out: cxa_atexit.c:100: __new_exitfn: Assertion `l != NULL' failed.
Aborted

Nota: – Come spiegato in precedenza, molte volte il comportamento della chiamata di sistema vfork non è prevedibile. Come nel caso precedente, ha stampato prima una volta e dopo due ma ha interrotto la chiamata con la funzione _exit(). È meglio usare la chiamata di sistema fork se non diversamente ed evitare di usare vfork il più possibile.

Differenze tra fork() e vfork()

Vfork() comportamento spiegato in maggior dettaglio nel programma sottostante.

[email protected] ~}$ cat vfork_advanced.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
    int n =10;
    pid_t pid = vfork(); //creating the child process
    if (pid == 0)          //if this is a chile process
    {
        printf("Child process started\n");
    }
    else//parent process execution
    {
        printf("Now i am coming back to parent process\n");
    }
    printf("value of n: %d \n",n); //sample printing to check "n" value
    return 0;
}
[email protected] ~}$ cc vfork_advanced.c
[email protected] ~}$ ./a.out
Child process started
value of n: 10
Now i am coming back to parent process
value of n: 594325573
a.out: cxa_atexit.c:100: __new_exitfn: Assertion `l != NULL' failed.
Aborted

Nota: Anche in questo caso se osservi il risultato di vfork non è definito. Il valore di "n" è stato stampato per la prima volta come 10, che è previsto. Ma la prossima volta nel processo padre ha stampato un valore spazzatura.

aspetta()

wait() la chiamata di sistema sospende l'esecuzione del processo corrente fino a quando un figlio non è uscito o fino a quando non è stato consegnato un segnale la cui azione è terminare il processo corrente o chiamare il gestore del segnale.

pid_t wait(int * status);

Ci sono altre chiamate di sistema relative all'attesa come di seguito,

1) waitpid() :sospende l'esecuzione del processo corrente fino a quando un figlio come specificato dagli argomenti pid non è uscito o fino a quando non viene consegnato un segnale.

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

2) aspetta 3() :Sospende l'esecuzione del processo in corso fino a quando un bambino non è uscito o fino a quando non viene consegnato il segnale.

pid_t wait3(int *status, int options, struct rusage *rusage);

3) aspetta4() :come wait3() ma include il valore pid di pid_t.

pid_t wait3(pid_t pid, int *status, int options, struct rusage *rusage);

exec()

exec() famiglia di  funzioni o chiamate di sistema sostituisce l'immagine di processo corrente con la nuova immagine di processo.

Ci sono funzioni come execl , execlp ,esegui ,execv , execvp e execvpe vengono utilizzati per eseguire un file.

Queste funzioni sono combinazioni di array di puntatori a stringhe con terminazione nulla che rappresentano l'elenco di argomenti, questo avrà una variabile di percorso con alcune combinazioni di variabili di ambiente.

exit()

Questa funzione viene utilizzata per la normale terminazione del processo. Lo stato del processo viene acquisito per riferimento futuro. Esistono altre funzioni simili exit(3) e _exit(). , che vengono utilizzati in base al processo in uscita che si desidera utilizzare o acquisire.

Conclusione:-

Le combinazioni di tutte queste chiamate/funzioni di sistema vengono utilizzate per la creazione, l'esecuzione e la modifica dei processi. Anche questi sono chiamati insieme di funzioni di spawn "shell". È necessario utilizzare queste funzioni con cautela tenendo presente il risultato e il comportamento.


Linux
  1. Come utilizzare gli snapshot LVM per ripristinare i sistemi Linux

  2. Come installare e utilizzare Git nel sistema Linux

  3. Come installare e utilizzare Telnet su sistemi Linux

  4. Come usare i comandi strace e ltrace in Linux

  5. Come installare e utilizzare Sguardi per monitorare i sistemi Linux

Come installare e utilizzare Skype su sistema Linux. Ora è più facile

Come installare e utilizzare il compilatore GCC su sistema Linux

Come montare e utilizzare un'unità exFAT su un sistema Linux

Come installare e utilizzare Tmux (Terminal Multiplexer) nel sistema Linux

Come installare e utilizzare AsciiDoc nel sistema Linux

Come installare e utilizzare l'emulatore di terminale Konsole nel sistema Linux