Chiamata di sistema fork in C

Fork System Call C



La chiamata di sistema fork() viene utilizzata per creare processi figlio in un programma C. fork() viene utilizzato dove è richiesta l'elaborazione parallela nell'applicazione. La funzione di sistema fork() è definita nelle intestazioni sys/types.h e unistd.h . In un programma in cui usi fork, devi anche usare la chiamata di sistema wait(). La chiamata di sistema wait() viene utilizzata per attendere nel processo padre il completamento del processo figlio. Per terminare un processo figlio, la chiamata di sistema exit() viene utilizzata nel processo figlio. La funzione wait() è definita nell'intestazione sys/wait.h e la funzione exit() è definita nell'intestazione stdlib.h .

Fig 1: Flusso di lavoro di base fork()

Fig 1: Flusso di lavoro di base fork()







In questo articolo, ti mostrerò come utilizzare la chiamata di sistema fork() per creare processi figlio in C. Quindi, iniziamo.



fork() Sintassi e valore di ritorno:

La sintassi della funzione di sistema fork() è la seguente:



pid_t fork(vuoto);

La funzione di sistema fork() non accetta alcun argomento. Restituisce un intero del tipo pid_t .





In caso di successo, fork() restituisce il PID del processo figlio che è maggiore di 0. All'interno del processo figlio, il valore restituito è 0. Se fork() fallisce, restituisce -1.

Semplice fork() Esempio:

Di seguito viene fornito un semplice esempio di fork():



#includere
#includere
#includere
#includere
#includere

intprincipale(vuoto) {
pid_t pid=forchetta();

Se(pid== 0) {
printf ('Figlio => PPID: %d PID: %d ',getppid(),getpid());
Uscita (EXIT_SUCCESS);
}
altro Se(pid> 0) {
printf ('Genitore => PID: %d ',getpid());
printf ('In attesa che il processo figlio finisca. ');
aspettare(NULLO);
printf ('Processo figlio terminato. ');
}
altro {
printf ('Impossibile creare un processo figlio. ');
}

RestituzioneEXIT_SUCCESS;
}

Qui, ho usato fork() per creare un processo figlio dal processo principale/genitore. Quindi, ho stampato il PID (ID processo) e il PPID (ID processo genitore) dal processo figlio e padre. Sul processo padre wait(NULL) viene utilizzato per attendere il completamento del processo figlio. Sul processo figlio, viene utilizzata exit() per terminare il processo figlio. Come puoi vedere, il PID del processo padre è il PPID del processo figlio. Quindi, il processo bambino 24738 appartiene al processo genitore 24731 .

Puoi anche utilizzare le funzioni per rendere il tuo programma più modulare. Ecco, ho usato processTask() e genitoreAttività() funzioni rispettivamente per i processi figlio e padre. Questo è il modo in cui viene effettivamente utilizzato fork().

#includere
#includere
#includere
#includere
#includere

vuotofiglioCompito() {
printf ('Ciao mondo ');
}

vuotogenitoreAttività() {
printf ('Compito principale. ');
}

intprincipale(vuoto) {
pid_t pid=forchetta();

Se(pid== 0) {
figlioCompito();
Uscita (EXIT_SUCCESS);
}
altro Se(pid> 0) {
aspettare(NULLO);
genitoreAttività();
}
altro {
printf ('Impossibile creare un processo figlio.');
}

RestituzioneEXIT_SUCCESS;
}

L'output del programma precedente:

Esecuzione di più processi figlio utilizzando fork() e Loop:

Puoi anche usare il ciclo per creare tutti i processi figlio di cui hai bisogno. Nell'esempio seguente, ho creato 5 processi figlio utilizzando il ciclo for. Ho anche stampato il PID e il PPID dai processi figlio.

#includere
#includere
#includere
#includere
#includere

intprincipale(vuoto) {
per(intio= 1;io<= 5;io++) {
pid_t pid=forchetta();

Se(pid== 0) {
printf ('Processo figlio => PPID=%d, PID=%d ',getppid(),getpid());
Uscita (0);
}
altro {
printf ('Processo padre => PID=%d ',getpid());
printf ('In attesa che i processi figlio finiscano... ');
aspettare(NULLO);
printf ('processo figlio terminato. ');
}
}

RestituzioneEXIT_SUCCESS;
}

Come puoi vedere, l'ID del processo padre è lo stesso in tutti i processi figlio. Quindi, appartengono tutti allo stesso genitore. Eseguono anche in modo lineare. Uno dopo l'altro. Il controllo dei processi figlio è un compito sofisticato. Se impari di più sulla programmazione del sistema Linux e su come funziona, sarai in grado di controllare il flusso di questi processi come preferisci.

Esempio di vita reale:

Diversi calcoli matematici complessi come md5, sha256 ecc. La generazione di hash richiede molta potenza di elaborazione. Invece di calcolare cose del genere nello stesso processo del programma principale, puoi semplicemente calcolare l'hash su un processo figlio e restituire l'hash al processo principale.

Nell'esempio seguente, ho generato un codice PIN a 4 cifre in un processo figlio e l'ho inviato al processo padre, il programma principale. Quindi, ho stampato il codice PIN da lì.

#includere
#includere
#includere
#includere
#includere

intgetPIN() {
// usa PPID e PID come seme
srand (getpid() +getppid());
intsegreto= 1000 + riga () % 9000;
Restituzionesegreto;
}

intprincipale(vuoto) {
intfd[2];
tubo(fd);
pid_t pid=forchetta();

Se(pid> 0) {
chiudere(0);
chiudere(fd[1]);
dopo(fd[0]);

intNumero segreto;
taglia_treadBytes=leggere(fd[0], &Numero segreto, taglia di(Numero segreto));

printf ('In attesa del PIN... ');
aspettare(NULLO);
printf ('Byte letti: %ld ',readBytes);
printf ('PIN: %d ',Numero segreto);
}
altro Se(pid== 0) {
chiudere(1);
chiudere(fd[0]);
dopo(fd[1]);

intsegreto=getPIN();
Scrivi(fd[1], &segreto, taglia di(segreto));
Uscita (EXIT_SUCCESS);
}

RestituzioneEXIT_SUCCESS;
}

Come puoi vedere, ogni volta che eseguo il programma, ricevo un codice PIN di 4 cifre diverso.

Quindi, questo è fondamentalmente il modo in cui usi la chiamata di sistema fork() in Linux. Grazie per aver letto questo articolo.