Perché il meccanismo di creazione del processo predefinito è fork?


46

La chiamata di sistema UNIX per la creazione del processo, fork (), crea un processo figlio copiando il processo principale. La mia comprensione è che questo è quasi sempre seguito da una chiamata a exec () per sostituire lo spazio di memoria del processo figlio (incluso il segmento di testo). Copiare lo spazio di memoria del genitore in fork () mi è sempre sembrato dispendioso (anche se mi rendo conto che lo spreco può essere minimizzato rendendo i segmenti di memoria copia-su-scrittura in modo da copiare solo i puntatori). Ad ogni modo, qualcuno sa perché questo approccio di duplicazione è necessario per la creazione del processo?


3
Si noti che la fork(2)pagina man sotto Linux dice: Under Linux, fork() is implemented using copy-on-write pages, so the only penalty that it incurs is the time and memory required to duplicate the parent's page tables, and to create a unique task structure for the child. Immagino (ma non lo so per certo) che questo è il caso di altri gusti Unix moderni.
Larks

4
L'originale, PDP-11 Unix, ha davvero copiato tutti i byte di un processo a fork: ma aveva solo 64 KB di eseguibili e al massimo 64 KB di dati, quindi non era un onere enorme, anche nel 1975. Vorrei suppongo che OGNI unix e unix-a-like dal 1990 hanno avuto segmenti di testo copy-on-write, quindi non sono nemmeno sicuro del motivo per cui libri e articoli diffondano più "problemi di prestazioni con fork".
Bruce Ediger,

Oggi fork è implementato in modo simile a vfork ( openbsd.org/cgi-bin/… ). È efficiente, non ti preoccupare.
Aki,

Si noti inoltre che ci sono molti usi in cui non si esegue dopo un fork (o almeno non si esegue immediatamente): pensare a pipe e server Web.
jfg956,

Potresti essere lento. Ma come dice @cjm, guarda l'alternativa che Microsoft utilizza CreateProcess, hanno dovuto implementare i thread in anticipo (potrebbe essere l'unica cosa su cui conducono), perché CreateProcess è lento. (Avevano anche bisogno di discussioni perché selecterano rotte, ma questa è un'altra storia).
ctrl-alt-delor,

Risposte:


57

È per semplificare l'interfaccia. L'alternativa forke execsarebbe qualcosa come la funzione CreateProcess di Windows . Notare quanti parametri CreateProcessha, e molti di loro sono strutture con ancora più parametri. Questo perché tutto ciò che potresti voler controllare sul nuovo processo deve essere passato a CreateProcess. In realtà, CreateProcessnon ha abbastanza parametri, quindi Microsoft ha dovuto aggiungere CreateProcessAsUser e CreateProcessWithLogonW .

Con il fork/execmodello, non hai bisogno di tutti quei parametri. Invece, alcuni attributi del processo sono preservati exec. Ciò ti consente di forkmodificare gli attributi di processo desiderati (utilizzando le stesse funzioni che utilizzeresti normalmente) e quindi exec . In Linux, forknon ha parametri e ne execveha solo 3: il programma da eseguire, la riga di comando da assegnare e il suo ambiente. (Esistono altre execfunzioni, ma sono solo i wrapper execveforniti dalla libreria C per semplificare i casi d'uso comuni.)

Se si vuole iniziare un processo con una directory corrente diversa: fork, chdir, exec.

Se si desidera reindirizzare stdin / stdout: fork, vicino / file aperti, exec.

Se si desidera utenti interruttore: fork, setuid, exec.

Tutte queste cose possono essere combinate secondo necessità. Se qualcuno presenta un nuovo tipo di attributo di processo, non è necessario cambiare forke exec.

Come accennato, gli Unix più moderni usano il copy-on-write, quindi forknon comportano un sovraccarico significativo.


16
Spiegazione eccellente. "Coloro che non capiscono UNIX sono condannati a reinventarlo, male." - Henry Spencer
Kyle Jones

1
Grazie! Hai un riferimento, per caso?
Ellen Spertus,

1
@Aki, no, CreateProcess () crea letteralmente un nuovo processo e lo crea da zero, senza biforcazione.
psusi,

2
Ma non deve esserci un equivalente di CreateProcess () da qualche parte in Unix? Altrimenti come viene creato il primo processo? A differenza di un dio creatore mitologico, il primo processo non può biforcarsi () dal nulla. ;-)
Steven lunedì

2
@StevenMonday, sì, ma è nel codice di inizializzazione del kernel e non accessibile dall'esterno. Non ha bisogno di tutti quei parametri perché quasi tutto è hardcoded. Può solo creare l'ID processo 1, ovvero il processo init. Successivamente, i processi vengono creati solo mediante il fork.
cjm

5

In aggiunta alla risposta del cjm, la specifica Unix singola definisce una funzione denominata vfork(). Quella funzione funziona come fork, tranne per il fatto che il processo biforcuto ha un comportamento indefinito se fa qualcosa di diverso dal provare a chiamare una funzione familiare exec, o chiamare _exit().

Quindi praticamente l'unico uso con un comportamento definito è:

pid_t ret = vfork();
if(ret == 0)
{
    exec(...);
    _exit(EXIT_FAILURE); //in case exec failed for any reason.
}

Quindi cosa fa vfork? È economico fork. Nelle implementazioni senza copia su scrittura, il processo risultante condividerà lo spazio di memoria con il processo originale (da cui il comportamento indefinito). Nelle implementazioni con copia su scrittura, vforkè consentito essere identici a fork(), poiché le implementazioni di copia su scrittura sono veloci.

C'è anche la posix_spawnfunzione opzionale (e una posix_spawnpfunzione) che può creare direttamente un nuovo processo. (È anche consentito implementarli con una chiamata in libreria utilizzando forke exece viene fornita un'implementazione di esempio.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.