2010-03-07 17 views
6

Ho letto di fork e da quello che ho capito, il processo è clonato ma quale processo? Lo script stesso o il processo che ha lanciato lo script?Cosa succede quando un processo è biforcato?

Ad esempio:

Io corro rTorrent sulla mia macchina e quando un torrente completa, ho uno script eseguito contro di essa. Questo script recupera i dati dal Web in modo che siano necessari alcuni secondi. Durante questo periodo, il mio processo di rtorrent è congelato. Così ho fatto la forcella script utilizzando il seguente

my $pid = fork(); 
if ($pid == 0) { blah blah blah; exit 0; } 

Se eseguo questo script dalla CLI, ritorna alla shell all'interno di un secondo mentre viene eseguito in background, esattamente come volevo. Tuttavia, quando lo eseguo da rTorrent, sembra essere ancora più lento di prima. Quindi, che cosa era esattamente biforcuta? Il processo di rtorrent ha clonato se stesso e il mio script ha funzionato, o il mio script ha clonato se stesso? Spero che abbia senso.

+1

Iniziare inserendo uno snippet di perl funzionante. –

+2

Provare a eseguire rTorrent in strace e vedere cosa sta bloccando quando lo script è in esecuzione. Questo potrebbe dare un indizio. Stavo pensando che avrebbe potuto aspettare() sul processo del nipote, ma sembra che il comportamento non sia effettivamente possibile usando le chiamate di sistema tradizionali. – jdizzle

risposta

2

Per rispondere alla domanda nominale, dal momento che si è commentato che la risposta accettata non riesce a farlo, fork influisce sul processo in cui viene chiamato.Nel tuo esempio di rTorrent spawn un processo Perl che chiama quindi fork, è il processo Perl che è duplicato, poiché era il processo Perl che chiamava fork.

Nel caso generale, non esiste un modo per un processo per fork qualsiasi processo diverso da se stesso. Se fosse possibile dire a un altro processo arbitrario di andare direttamente a fork, ciò non comporterebbe problemi di sicurezza e di prestazioni.

+2

Oltre ad aprire la possibilità per un sacco di battute: "hey you! Go fork yourself!" "no, ti forchetta!" – Ether

6

La funzione fork() restituisce DUE VOLTE! Una volta nel processo principale e una volta nel processo figlio. In generale, entrambi i processi sono IDENTICI in tutti i modi, come se CIASCUNO fosse appena tornato da fork(). L'unica differenza è che in uno, il valore restituito da fork() è 0 e nell'altro è diverso da zero (il PID del processo figlio).

Quindi, qualsiasi processo eseguisse lo script Perl (se è un interprete Perl incorporato in rTorrent allora rTorrent sarebbe il processo) verrebbe duplicato esattamente nel punto in cui è avvenuto lo fork().

+0

Non penso che questo stia davvero rispondendo alla sua domanda ... – jdizzle

+2

@jdizzle - Probabilmente perché la domanda non ha molto senso, perché "qualcuno" non capisce il processo e le idee di forking. Spiegare alcuni fatti potrebbe aiutare :) – viraptor

+1

@viraptor - Sento che qualcuno ha una buona conoscenza di fork() ing. La domanda riguarda davvero l'implementazione di rTorrent. – jdizzle

3

L'intero processo contenente le forcelle dell'interprete. Fortunatamente la memoria è copy-on-write, quindi non è necessario copiare tutta la memoria del processo per poterla utilizzare. Tuttavia, elementi come i descrittori di file rimangono aperti. Ciò consente ai processi figli di gestirli, ma può causare problemi se non vengono chiusi in modo appropriato. In generale, fork() non deve essere utilizzato in un interprete incorporato tranne in caso di estrema durezza.

+0

Meh. Non è che questa è la fine del mondo per fork() in perl sulla macchina di un utente finale. Sono d'accordo che probabilmente è una cattiva pratica da usare spesso (dato che è un punto maturo per un collo di bottiglia). – jdizzle

+0

Se si tratta di una cattiva pratica, esiste un metodo alternativo per impedire il blocco? – somebody

2

Il mio consiglio sarebbe "non farlo".

Se l'interprete Perl è incorporato nel processo di rtorrent, hai quasi certamente biforcato un intero processo di rtorrent, i cui effetti sono probabilmente mal definiti. In genere è una cattiva idea giocare con roba di livello di processo in un interprete incorporato indipendentemente dalla lingua.

C'è un'eccellente possibilità che un qualche tipo di blocco non venga rilasciato correttamente o che i thread all'interno dei processi stiano procedendo in modo non intenzionale e possibilmente in competizione.

+0

Quanto è comune il collegamento effettivo con l'interprete perl? Non sarebbe molto più pratico (e sicuro) per system() questo tipo di chiamate? – jdizzle

+0

Vero che chiamare 'fork()' in un programma multithread sta causando problemi. Se si limita ciò che accade nel processo figlio, tuttavia, non è così male. Ad esempio, non chiamare nulla che deve acquisire un blocco in modalità utente. Ma l'uso tipico del seguente 'fork()' con 'dup2()', 'close()', 'execve()' ecc dovrebbe essere sicuro. – asveikau

+0

@jdizzle: il collegamento con un interprete esterno, Perl o altro, è molto comune, ma non è del tutto chiaro dalla domanda se questo sia il caso o no con questo programma. Tuttavia, rileggendo, potresti avere ragione sul fatto che system() sia in uso. –

4

Credo di aver trovato il problema osservando la fonte di rTorrent. Per alcuni processi, leggerà tutto l'output inviato a stdout prima di continuare. Se questo sta accadendo al tuo processo, rTorrent bloccherà fino a quando non chiuderai il processo di stdout. Poiché si esegue la forking, il processo figlio condivide lo stesso stdout del genitore. Il processo genitore verrà chiuso, ma la pipe rimane aperta (perché il processo figlio è ancora in esecuzione). Se avessi fatto una scusa di rTorrent, avrei scommesso che sarebbe stato bloccato su questa chiamata read() durante l'esecuzione del comando.

Provare a chiudere/reindirizzare lo stdout nello script perl prima dello fork().

+0

Risolve il problema, ma non risponde alla domanda nominale. Mi piacerebbe. – darch

+0

@darch - il titolo della domanda è in realtà pertinente al problema che qualcuno sta cercando di risolvere – jdizzle

+0

Ho trovato questo molto utile, quindi grazie per averlo inserito anche se "non ha risposto alla domanda nominale", @jdizzle :) –

1

Quando creiamo un processo tramite fork, il processo figlio avrà la copia dello spazio indirizzo. Quindi anche il bambino può utilizzare lo spazio indirizzo. Inoltre può accedere ai file aperti dal genitore. Possiamo avere il controllo sul bambino. Per ottenere lo stato completo del bambino possiamo usare aspettare.

Problemi correlati