Fork System Call Linux

Fork System Call Linux



La chiamata di sistema fork viene utilizzata per creare nuovi processi. Il processo appena creato è il processo figlio. Il processo che chiama fork e crea un nuovo processo è il processo padre. I processi figlio e padre vengono eseguiti contemporaneamente.

Ma i processi figlio e padre risiedono su spazi di memoria differenti. Questi spazi di memoria hanno lo stesso contenuto e qualunque operazione venga eseguita da un processo non influenzerà l'altro processo.







Quando viene creato il processo figlio; ora entrambi i processi avranno lo stesso Program Counter (PC), quindi entrambi questi processi punteranno alla stessa istruzione successiva. I file aperti dal processo padre saranno gli stessi per il processo figlio.



Il processo figlio è esattamente uguale al suo genitore ma c'è una differenza negli ID dei processi:



  1. L'ID processo del processo figlio è un ID processo univoco diverso dagli ID di tutti gli altri processi esistenti.
  2. L'ID processo genitore sarà lo stesso dell'ID processo del genitore del figlio.

Proprietà del processo figlio

Di seguito sono riportate alcune delle proprietà che detiene un processo figlio:





  1. I contatori della CPU e gli utilizzi delle risorse vengono inizializzati per essere reimpostati su zero.
  2. Quando il processo padre viene terminato, i processi figlio non ricevono alcun segnale perché l'attributo PR_SET_PDEATHSIG in prctl() viene reimpostato.
  3. Il thread utilizzato per chiamare fork() crea il processo figlio. Quindi l'indirizzo del processo figlio sarà lo stesso di quello del genitore.
  4. Il descrittore di file del processo padre viene ereditato dal processo figlio. Ad esempio, l'offset del file o lo stato dei flag e gli attributi di I/O saranno condivisi tra i descrittori di file dei processi figlio e padre. Quindi il descrittore di file della classe genitore farà riferimento allo stesso descrittore di file della classe figlio.
  5. I descrittori della coda dei messaggi aperti del processo padre vengono ereditati dal processo figlio. Ad esempio, se un descrittore di file contiene un messaggio nel processo padre, lo stesso messaggio sarà presente nel corrispondente descrittore di file del processo figlio. Quindi possiamo dire che i valori dei flag di questi descrittori di file sono gli stessi.
  6. Allo stesso modo, i flussi di directory aperti verranno ereditati dai processi figlio.
  7. Il valore di slack predefinito del timer della classe figlia è lo stesso del valore di slack del timer corrente della classe padre.

Proprietà che non sono ereditate dal processo figlio

Di seguito sono riportate alcune delle proprietà che non vengono ereditate da un processo figlio:

  1. Blocchi di memoria
  2. Il segnale in sospeso di una classe figlio è vuoto.
  3. Elabora i blocchi dei record associati (fcntl())
  4. Operazioni di I/O asincrone e contenuti di I/O.
  5. Notifiche di modifica della directory.
  6. I timer come alarm(), setitimer() non vengono ereditati dalla classe figlio.

fork() in Do

Non ci sono argomenti in fork() e il tipo restituito di fork() è intero. Devi includere i seguenti file di intestazione quando viene utilizzato fork():



#includere
#includere
#includere

Quando si lavora con fork(), può essere usato per type pid_t per i processi ID come pid_t è definito in .

Il file di intestazione è dove è definito fork(), quindi devi includerlo nel tuo programma per usare fork().

Il tipo restituito è definito in e la chiamata fork() è definita in . Pertanto, è necessario includere entrambi nel programma per utilizzare la chiamata di sistema fork().

Sintassi di fork()

La sintassi della chiamata di sistema fork() in Linux, Ubuntu è la seguente:

pid_t fork(void);

Nella sintassi il tipo restituito è pid_t . Quando il processo figlio viene creato con successo, il PID del processo figlio viene restituito nel processo padre e 0 verrà restituito al processo figlio stesso.

In caso di errore, viene restituito -1 al processo padre e il processo figlio non viene creato.

No arguments are passed to fork(). 

Esempio 1: chiamata fork()

Considera il seguente esempio in cui abbiamo usato la chiamata di sistema fork() per creare un nuovo processo figlio:

CODICE:

#includere
#includere
#includere

intprincipale()
{
forchetta();
printf ('Uso della chiamata di sistema fork() ');
Restituzione 0;
}

PRODUZIONE:

Utilizzo della chiamata di sistema fork()
Utilizzo della chiamata di sistema fork()

In questo programma, abbiamo usato fork(), questo creerà un nuovo processo figlio. Quando viene creato il processo figlio, sia il processo padre che il processo figlio punteranno all'istruzione successiva (stesso Program Counter). In questo modo le restanti istruzioni o istruzioni C verranno eseguite per il numero totale di tempi di processo, ovvero 2nvolte, dove n è il numero di chiamate di sistema fork().

Quindi quando la chiamata fork() viene usata una volta come sopra (21= 2) avremo il nostro output 2 volte.

Qui quando viene utilizzata la chiamata di sistema fork(), la struttura interna sarà simile a:

Considera il seguente caso in cui fork() viene usato 4 volte:

CODICE:

#includere
#includere
#includere

intprincipale()
{
forchetta();
forchetta();
forchetta();
forchetta();
printf ('Uso della chiamata di sistema fork()');
Restituzione 0;
}

Produzione:

Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call Using fork() system call 

Ora il numero totale di processi creati è 24= 16 e abbiamo la nostra istruzione print eseguita 16 volte.

Esempio 2: verificare se fork() ha avuto successo

Nell'esempio seguente abbiamo usato il costrutto decisionale per testare il valore (int) restituito da fork(). E vengono visualizzati i messaggi corrispondenti:

CODICE:

#includere
#includere
#includere

intprincipale()
{
pid_t p;
P=forchetta();
Se(P== -1)
{
printf ('Si è verificato un errore durante la chiamata a fork()');
}
Se(P==0)
{
printf ('Siamo nel processo del bambino');
}
altro
{
printf ('Siamo nel processo genitore');
}
Restituzione 0;
}

PRODUZIONE:

Siamo nel processo genitore
Siamo nel processo bambino

Nell'esempio sopra abbiamo usato il tipo pid_t che memorizzerà il valore di ritorno di fork(). fork() viene chiamato in linea:

P=forchetta();

Quindi il valore intero restituito da fork() viene memorizzato in p e quindi p viene confrontato per verificare se la nostra chiamata fork() ha avuto successo.

Quando viene utilizzata la chiamata fork() e il figlio viene creato con successo, l'id del processo figlio verrà restituito al processo padre e 0 verrà restituito al processo figlio. L'ID del processo figlio nel processo padre non sarà lo stesso del processo padre ID del processo figlio nel processo figlio stesso. Nel processo figlio l'ID del processo figlio sarà 0.

Con questo tutorial puoi vedere come iniziare con la chiamata di sistema fork in Linux.