GNU/Linux >> Linux Esercitazione >  >> Linux

Cosa succede quando un thread si biforca?

Il nuovo processo sarà figlio del thread principale che ha creato il thread. Penso.

fork crea un nuovo processo. Il genitore di un processo è un altro processo, non un thread. Quindi il genitore del nuovo processo è il vecchio processo.

Nota che il processo figlio avrà un solo thread perché fork duplica solo il (stack per il) thread che chiama fork . (Questo non è del tutto vero:l'intera memoria è duplicata, ma il processo figlio avrà un solo thread attivo.)

Se il suo genitore finisce per primo, il nuovo processo sarà collegato al processo init.

Se il genitore finisce per primo un SIGHUP segnale viene inviato al bambino. Se il bambino non esce a causa del SIGHUP otterrà init come suo nuovo genitore. Vedi anche le pagine man per nohup e signal(7) per ulteriori informazioni su SIGHUP .

E il suo genitore è il thread principale, non il thread che lo ha creato.

Il genitore di un processo è un processo, non un thread specifico, quindi non ha senso dire che il thread principale o figlio è il genitore. L'intero processo è il genitore.

Un'ultima nota:mescolare fili e forchetta deve essere fatto con cura. Alcune delle insidie ​​sono discusse qui.


Correggimi se sbaglio.

Andrà bene :)

Come fork() è una chiamata di sistema POSIX, il suo comportamento è ben definito:

Un processo deve essere creato con un singolo thread . Se un processo multi-thread chiama fork(), il nuovo processo deve contenere una replica del thread chiamante e il suo intero spazio degli indirizzi, possibilmente includendo gli stati dei mutex e altre risorse. Di conseguenza, per evitare errori, il processo figlio può eseguire solo operazioni con segnale asincrono sicuro fino a quando non viene chiamata una delle funzioni exec.

https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html

Un figlio biforcuto è un duplicato esatto del suo genitore, ma solo il thread che ha chiamato fork() nel genitore, esiste ancora nel figlio ed è il nuovo thread principale di quel figlio finché non chiami exec() .

La descrizione POSIX "deve essere creata con un singolo thread" è fuorviante poiché in effetti la maggior parte dell'implementazione creerà davvero un duplicato esatto del processo genitore, quindi anche tutti gli altri thread e la loro memoria sono duplicati, il che significa che i thread sono effettivamente lì , semplicemente non possono più essere eseguiti poiché il sistema non assegna loro alcun tempo di CPU; mancano infatti nella tabella dello scheduler dei thread del kernel.

Un'immagine mentale più semplice è la seguente:

Quando il genitore chiama fork, l'intero processo viene bloccato per un momento, duplicato atomicamente, quindi il genitore viene sbloccato nel suo insieme, ma nel figlio solo il thread che ha chiamato fork viene sbloccato, tutto il resto rimane bloccato.

Ecco perché non è sicuro eseguire determinate chiamate di sistema tra fork() e exec() come sottolineato anche dallo standard POSIX. Idealmente non dovresti fare molto di più che forse chiudere o duplicare descrittori di file, impostare o ripristinare gestori di segnale e quindi chiamare exec() .


Tuttavia, cosa accadrà se un thread crea un nuovo processo usando fork()?

Verrà creato un nuovo processo copiando i thread chiamanti spazio degli indirizzi (non l'intero spazio degli indirizzi del processo ). Generalmente è considerata una cattiva idea perché è molto difficile realizzarla correttamente. POSIX dice che il processo figlio (creato in un programma multi-thread) può chiamare solo funzioni async-signal-safe finché non chiama uno dei exec* funzioni.

Se il suo genitore finisce per primo, il nuovo processo sarà collegato a initprocess.

Il processo figlio è in genere ereditato dal processo init. Se il processo genitore è un processo di controllo (es. shell), allora POSIX richiede:

Se il processo è un processo di controllo, il segnale SIGHUP deve essere inviato a ciascun processo nel gruppo di processi in primo piano del terminale di controllo appartenente al processo chiamante.

Tuttavia, questo non è vero per la maggior parte dei processi poiché la maggior parte dei processi non controlla i processi.

E il suo genitore è il thread principale, non il thread che lo ha creato.

Il genitore del figlio fork sarà sempre il processo che ha chiamato fork(). Quindi, PPID è il processo figlio che sarà il PID del tuo programma.


problema deriva dal comportamento di fork(2) stesso. Ogni volta che un nuovo processo figlio viene creato con fork(2) il nuovo processo ottiene un nuovo spazio di indirizzi di memoria ma tutto ciò che è in memoria viene copiato dal vecchio processo (con copia su scrittura che non è vero al 100%, ma la semantica è la stessa).

Se chiamiamo fork(2) in un ambiente multi-thread, il thread che esegue la chiamata è ora il thread principale nel nuovo processo e tutti gli altri thread, che giravano nel processo genitore, sono morti. E tutto ciò che hanno fatto è stato lasciato esattamente com'era appena prima della chiamata a fork(2).

Ora immagina che questi altri thread stessero felicemente svolgendo il loro lavoro prima della chiamata a fork(2) e un paio di millisecondi dopo siano morti. E se qualcosa che questi thread ora morti hanno fatto non fosse destinato a essere lasciato esattamente così com'era?

Lasciate che vi faccia un esempio. Diciamo che il nostro thread principale (quello che chiameremo fork(2)) stava dormendo mentre avevamo molti altri thread che facevano felicemente del lavoro. Allocare memoria, scrivere su di essa, copiare da essa, scrivere su file, scrivere su un database e così via. Probabilmente stavano allocando la memoria con qualcosa come malloc(3).Beh, si scopre che malloc(3) usa un mutex internamente per garantire la sicurezza del filo. Ed è proprio questo il problema.

E se uno di questi thread stesse usando malloc(3) e avesse acquisito il lock del mutex esattamente nello stesso momento in cui il thread principale ha chiamato fork(2)? Nel nuovo processo figlio il blocco è ancora mantenuto - da un thread ora morto, che non lo restituirà mai.

Il nuovo processo figlio non avrà idea se sia sicuro usare malloc(3) o meno. Nel peggiore dei casi chiamerà malloc(3) e si bloccherà finché non acquisirà il lock, cosa che non accadrà mai, dato che il thread che dovrebbe restituirlo è morto. E questo è solo malloc(3). Pensa a tutti gli altri possibili mutex e blocchi nei driver di database, nelle librerie di gestione dei file, nelle librerie di rete e così via.

per una spiegazione completa puoi passare attraverso questo link.


Linux
  1. Cosa succede quando eseguo il comando Cat /proc/cpuinfo?

  2. Cosa succede esattamente quando eseguo un file nella shell?

  3. Cosa sono i segnali in sospeso?

  4. Cosa succede a un processo Linux multithread se riceve un segnale?

  5. Cosa succede quando un file che è stato impaginato al 100% nella cache della pagina viene modificato da un altro processo

Linux – Quando non dovrei uccidere -9 Un processo?

Linux:cosa succede quando esegui la sincronizzazione senza un percorso di destinazione??

Cos'è un processo ininterrotto?

Cosa succede se mv viene interrotto?

Cos'è un processo interrotto in Linux?

Cosa succede se elimino lost+found