it-swarm.com.de

Was ist der Zweck von Gabel ()?

In vielen Programmen und Manpages von Linux habe ich Code mit fork() gesehen. Warum müssen wir fork() verwenden und wozu dient es?

79
kar

fork() erstellt neue Prozesse in Unix. Wenn Sie fork aufrufen, erstellen Sie eine Kopie Ihres eigenen Prozesses, die über einen eigenen Adressraum verfügt. Dadurch können mehrere Tasks unabhängig voneinander ausgeführt werden, als ob sie den vollen Arbeitsspeicher der Maschine für sich alleine hätten.

Hier einige Beispiele für die Verwendung von fork:

  1. Ihre Shell verwendet fork, um die Programme auszuführen, die Sie von der Befehlszeile aus aufrufen.
  2. Webserver wie Apache verwenden fork, um mehrere Serverprozesse zu erstellen, von denen jeder Anforderungen in seinem eigenen Adressraum verarbeitet. Wenn einer stirbt oder Speicher verliert, sind andere davon nicht betroffen, so dass er als Fehlertoleranzmechanismus fungiert.
  3. Google Chrome verwendet fork, um jede Seite in einem separaten Prozess zu bearbeiten. Dadurch wird verhindert, dass clientseitiger Code auf einer Seite Ihren gesamten Browser herunterfährt.
  4. fork wird zum Erzeugen von Prozessen in einigen parallelen Programmen verwendet (z. B. mit MPI ). Beachten Sie, dass sich dies von der Verwendung von Threads unterscheidet, die keinen eigenen Adressraum haben und in einen Prozess existieren.
  5. Skriptsprachen verwenden fork indirekt, um untergeordnete Prozesse zu starten. Jedes Mal, wenn Sie einen Befehl wie subprocess.Popen in Python verwenden, fork Sie einen untergeordneten Prozess und lesen dessen Ausgabe. Dadurch können Programme zusammenarbeiten.

Die typische Verwendung von fork in einer Shell könnte in etwa wie folgt aussehen:

int child_process_id = fork();
if (child_process_id) {
    // Fork returns a valid pid in the parent process.  Parent executes this.

    // wait for the child process to complete
    waitpid(child_process_id, ...);  // omitted extra args for brevity

    // child process finished!
} else {
    // Fork returns 0 in the child process.  Child executes this.

    // new argv array for the child process
    const char *argv[] = {"arg1", "arg2", "arg3", NULL};

    // now start executing some other program
    exec("/path/to/a/program", argv);
}

Die Shell erzeugt mit exec einen untergeordneten Prozess, wartet, bis der Vorgang abgeschlossen ist, und fährt dann mit ihrer eigenen Ausführung fort. Beachten Sie, dass Sie Fork auf diese Weise nicht verwenden müssen. Sie können immer viele untergeordnete Prozesse erzeugen, wie dies bei einem parallelen Programm der Fall ist, und jeder kann ein Programm gleichzeitig ausführen. Grundsätzlich verwenden Sie fork(), wenn Sie neue Prozesse in einem Unix-System erstellen. Für das Windows-Äquivalent sehen Sie unter CreateProcess .

Wenn Sie mehr Beispiele und eine längere Erklärung wünschen, hat Wikipedia eine anständige Zusammenfassung. Und hier sind einige Folien hier, wie Prozesse, Threads und Parallelität in modernen Betriebssystemen funktionieren.

100
Todd Gamblin

mit Fork () erstellen Sie neue Prozesse. An dem Punkt, an dem Sie fork () aufgerufen haben, wird Ihr Prozess geklont, und zwei verschiedene Prozesse setzen die Ausführung von dort aus fort. Einer von ihnen, das untergeordnete, hat fork () return 0. Der andere, der übergeordnete, wird über gab () die PID (Prozess-ID) des untergeordneten Objekts zurückgeben.

Wenn Sie beispielsweise Folgendes in eine Shell eingeben, ruft das Shell-Programm fork () auf und führt dann den von Ihnen übergebenen Befehl (in diesem Fall telnetd) im untergeordneten Objekt aus, während das übergeordnete Element die Eingabeaufforderung ebenfalls erneut anzeigt als Nachricht, die die PID des Hintergrundprozesses angibt.

$ telnetd &

Aus dem Grund, warum Sie neue Prozesse erstellen, kann Ihr Betriebssystem auf diese Weise viele Aufgaben gleichzeitig ausführen. Aus diesem Grund können Sie ein Programm ausführen und während es ausgeführt wird, zu einem anderen Fenster wechseln und etwas anderes tun.

12

fork () wird zum Erstellen eines untergeordneten Prozesses verwendet. Wenn eine Funktion fork () aufgerufen wird, wird ein neuer Prozess erzeugt, und der Aufruf der Funktion fork () gibt einen anderen Wert für das untergeordnete Element und das übergeordnete Element zurück. 

Wenn der Rückgabewert 0 ist, wissen Sie, dass Sie der untergeordnete Prozess sind. Wenn der Rückgabewert eine Zahl ist (die zufällig die untergeordnete Prozess-ID ist), wissen Sie, dass Sie der übergeordnete Prozess sind. (und wenn es eine negative Zahl ist, war die Gabelung fehlgeschlagen und es wurde kein untergeordneter Prozess erstellt.)

http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

9
Wadih M.

fork () erstellt einen neuen untergeordneten Prozess, der mit dem übergeordneten identisch ist. Alles, was Sie danach im Code ausführen, wird von beiden Prozessen ausgeführt. Dies ist sehr nützlich, wenn Sie beispielsweise über einen Server verfügen und mehrere Anforderungen bearbeiten möchten.

6
cloudhead

mit fork () wird grundsätzlich ein untergeordneter Prozess für den Prozess erstellt, in dem Sie diese Funktion aufrufen. Wenn Sie eine Fork () aufrufen, wird eine Null für die untergeordnete ID zurückgegeben.

pid=fork()
if pid==0
//this is the child process
else if pid!=0
//this is the parent process

auf diese Weise können Sie verschiedene Aktionen für das übergeordnete Element und das untergeordnete Element bereitstellen und die Multithreading-Funktion verwenden.

6
Nave

Der Systemaufruf fork () wird zum Erstellen von Prozessen verwendet. Es nimmt keine Argumente und gibt eine Prozess-ID zurück. Der Zweck von fork () besteht darin, einen neuen Prozess zu erstellen, der zum untergeordneten Prozess des Aufrufers wird. Nachdem ein neuer untergeordneter Prozess erstellt wurde, führen beide Prozesse den nächsten Befehl nach dem Systemaufruf von fork () aus. Deshalb müssen wir den Elternteil vom Kind unterscheiden. Dazu können Sie den zurückgegebenen Wert von fork () testen:

Wenn Fork () einen negativen Wert zurückgibt, war die Erstellung eines untergeordneten Prozesses nicht erfolgreich. . Fork () gibt den neu erstellten untergeordneten Prozess eine Null zurück. _ Fork () gibt einen positiven Wert zurück, die Prozess-ID des Kindprozess an den Elternteil. Die zurückgegebene Prozess-ID ist vom Typ pid_t in sys/types.h definiert. Normalerweise ist die Prozess-ID eine ganze Zahl. Außerdem kann ein Prozess die Funktion getpid () verwenden, um die diesem Prozess zugewiesene Prozess-ID abzurufen. Nach einem Systemaufruf von fork () kann ein einfacher Test feststellen, welcher Prozess der untergeordnete Prozess ist. Bitte beachten Sie, dass Unix eine genaue Kopie des Adressraums der Eltern erstellt und dem Kind gibt. Daher verfügen der übergeordnete und der untergeordnete Prozess über separate Adressräume.

Verstehen wir es anhand eines Beispiels, um die obigen Punkte klarer zu machen. Dieses Beispiel unterscheidet nicht zwischen übergeordneten und untergeordneten Prozessen. 

#include  <stdio.h>
#include  <string.h>
#include  <sys/types.h>

#define   MAX_COUNT  200
#define   BUF_SIZE   100

void  main(void)
{
     pid_t  pid;
     int    i;
     char   buf[BUF_SIZE];

     fork();
     pid = getpid();
     for (i = 1; i <= MAX_COUNT; i++) {
          sprintf(buf, "This line is from pid %d, value = %d\n", pid, i);
          write(1, buf, strlen(buf));
     } 
}

Angenommen, das obige Programm wird bis zum Aufruf von fork () ausgeführt.

Wenn der Aufruf von fork () erfolgreich ausgeführt wird, erstellt Unix zwei identische Kopien von Adressräumen, eine für das übergeordnete und die andere für das untergeordnete Element .. _ Beide Prozesse starten ihre Ausführung bei der nächsten Anweisung, die auf das fork () folgt. Anruf. In diesem Fall beginnen beide Prozesse ihre Ausführung bei der Zuweisung 

pid = .....;

Beide Prozesse starten ihre Ausführung direkt nach dem Systemaufruf fork (). Da beide Prozesse identische, aber getrennte Adressräume haben, haben die vor dem Aufruf von fork () initialisierten Variablen in beiden Adressräumen die gleichen Werte. Da jeder Prozess über einen eigenen Adressraum verfügt, sind alle Änderungen unabhängig von den anderen. Das heißt, wenn das übergeordnete Element den Wert seiner Variablen ändert, wirkt sich die Änderung nur auf die Variable im Adressraum des übergeordneten Prozesses aus. Andere Adressbereiche, die von Fork () - Aufrufen erstellt wurden, sind nicht betroffen, obwohl sie identische Variablennamen haben.

Was ist der Grund für die Verwendung von write anstelle von printf? Dies liegt daran, dass printf () "gepuffert" ist, was bedeutet, dass printf () die Ausgabe eines Prozesses zusammenfasst. Während die Ausgabe für den übergeordneten Prozess gepuffert wird, verwendet das untergeordnete Programm möglicherweise auch printf, um Informationen auszudrucken, die ebenfalls gepuffert werden. Da die Ausgabe nicht sofort an den Bildschirm gesendet wird, erhalten Sie möglicherweise nicht die richtige Reihenfolge des erwarteten Ergebnisses. Schlimmer noch, die Ausgabe der beiden Prozesse kann auf seltsame Weise gemischt werden. Um dieses Problem zu umgehen, können Sie den "ungepufferten" Schreibvorgang verwenden.

Wenn Sie dieses Programm ausführen, wird möglicherweise Folgendes auf dem Bildschirm angezeigt:

................
This line is from pid 3456, value 13
This line is from pid 3456, value 14
     ................
This line is from pid 3456, value 20
This line is from pid 4617, value 100
This line is from pid 4617, value 101
     ................
This line is from pid 3456, value 21
This line is from pid 3456, value 22
     ................

Die Prozess-ID 3456 kann diejenige sein, die dem übergeordneten oder untergeordneten Element zugewiesen ist. Aufgrund der Tatsache, dass diese Prozesse gleichzeitig ablaufen, werden ihre Ausgangsleitungen auf unvorhersehbare Weise miteinander vermischt. Darüber hinaus wird die Reihenfolge dieser Zeilen vom CPU-Scheduler festgelegt. Wenn Sie dieses Programm erneut ausführen, erhalten Sie möglicherweise ein völlig anderes Ergebnis.

4
cpp-coder

Sie müssen in der täglichen Programmierung wahrscheinlich keine Forks verwenden, wenn Sie Anwendungen schreiben.

Selbst wenn Sie möchten, dass Ihr Programm ein anderes Programm startet, um eine Aufgabe zu erledigen, gibt es andere einfachere Schnittstellen, die Fork hinter den Kulissen verwenden, z.

Wenn Sie beispielsweise möchten, dass Ihre Anwendung ein anderes Programm wie bc startet, um Berechnungen für Sie auszuführen, können Sie 'system' verwenden, um es auszuführen. Das System führt einen 'Fork' aus, um einen neuen Prozess zu erstellen, und dann einen 'Exec', um diesen Prozess in bc umzuwandeln. Sobald bc abgeschlossen ist, gibt das System die Kontrolle an Ihr Programm zurück.

Sie können auch andere Programme asynchron ausführen, aber ich kann mich nicht erinnern, wie.

Wenn Sie Server, Shells, Viren oder Betriebssysteme schreiben, möchten Sie eher Fork verwenden.

4
Alex Brown

Gabel schafft neue Prozesse. Ohne Fork hätten Sie ein Unix-System, das nur init ausführen könnte.

4
Stephen

Mit Fork () werden neue Prozesse erstellt, während jeder Körper geschrieben hat.

Hier ist mein Code, der Prozesse in der Form eines binären Baums erstellt ....... Er fordert Sie auf, die Anzahl der Ebenen zu scannen, bis zu der Sie Prozesse im binären Baum erstellen möchten

#include<unistd.h> 
#include<fcntl.h> 
#include<stdlib.h>   
int main() 
{
int t1,t2,p,i,n,ab;
p=getpid();                
printf("enter the number of levels\n");fflush(stdout);
scanf("%d",&n);                
printf("root %d\n",p);fflush(stdout);
for(i=1;i<n;i++)    
{        
    t1=fork();

    if(t1!=0)
        t2=fork();        
    if(t1!=0 && t2!=0)        
        break;            
    printf("child pid %d   parent pid %d\n",getpid(),getppid());fflush(stdout);
}   
    waitpid(t1,&ab,0);
    waitpid(t2,&ab,0);
return 0;
}

AUSGABE

  enter the number of levels
  3
  root 20665
  child pid 20670   parent pid 20665
  child pid 20669   parent pid 20665
  child pid 20672   parent pid 20670
  child pid 20671   parent pid 20670
  child pid 20674   parent pid 20669
  child pid 20673   parent pid 20669
3
Anil Kumar Arya

Multiprocessing ist für das Computing von zentraler Bedeutung. Beispielsweise können Sie mit Ihrem IE oder Firefox einen Prozess zum Herunterladen einer Datei für Sie erstellen, während Sie noch im Internet surfen. Wenn Sie ein Dokument in einem Textverarbeitungsprogramm ausdrucken, können Sie dennoch verschiedene Seiten anzeigen und noch etwas bearbeiten.

fork() wird verwendet, um einen untergeordneten Prozess zu erzeugen. Normalerweise wird es in ähnlichen Situationen wie beim Threading verwendet, es gibt jedoch Unterschiede. Im Gegensatz zu Threads erstellt fork() ganze separate Prozesse. Dies bedeutet, dass das untergeordnete Element und das übergeordnete Element an dem Punkt, an dem fork() aufgerufen wird, direkte Kopien voneinander sind. Sie sind vollständig voneinander getrennt, und beide können nicht auf den Speicherplatz des anderen zugreifen (ohne zu dem Bei normalen Problemen greifen Sie in den Speicher eines anderen Programms).

fork() wird noch von einigen Serveranwendungen verwendet, meistens auf einem * NIX-Computer, der als root ausgeführt wird und Berechtigungen vor der Verarbeitung von Benutzeranforderungen löscht. Es gibt noch einige andere Anwendungsfälle, aber die meisten Leute haben sich jetzt zum Multithreading bewegt.

1

Zuerst muss man verstehen, was ein Fork () -Systemaufruf ist. Lassen Sie mich erklären

  1. der Systemaufruf von fork () erstellt das genaue Duplikat des übergeordneten Prozesses. Er erstellt das Duplikat von übergeordnetem Stack, Heap, initialisierten Daten und nicht initialisierten Daten und teilt den Code im schreibgeschützten Modus mit dem übergeordneten Prozess.

  2. Der Fork-Systemaufruf kopiert den Speicher auf der Copy-on-Write-Basis. Dies bedeutet, dass untergeordnete Elemente auf der Seite des virtuellen Speichers erstellt werden, wenn ein Kopiervorgang erforderlich ist.

Jetzt Zweck der Gabel ():

  1. Fork () kann an dem Ort verwendet werden, an dem die Arbeitsteilung so ist, wie ein Server mehrere Clients abwickeln muss. Daher muss das übergeordnete Element die Verbindung regelmäßig annehmen.
1
Sandeep_black

Das Grundprinzip von fork () im Vergleich zu einer exec () - Funktion zum Initiieren eines neuen Prozesses wird in einer Antwort auf eine ähnliche Frage beim Unix-Stack-Austausch erläutert.

Da der aktuelle Prozess von Fork kopiert wird, werden im Wesentlichen alle möglichen Optionen für einen Prozess festgelegt, so dass der Programmierer sie nicht zur Verfügung stellt.

Im Windows-Betriebssystem hingegen müssen Programmierer die CreateProcess-Funktion verwenden, die um ein Vielfaches komplizierter ist und zum Bestimmen der Parameter des neuen Prozesses eine vielfältige Struktur erfordert.

Zusammenfassend lässt sich sagen, dass der Grund für das Abzweigen (im Vergleich zum Ausführen) die Vereinfachung beim Erstellen neuer Prozesse ist.

0
Tyler Durden

Mit der Funktion fork () wird ein neuer Prozess erstellt, indem der vorhandene Prozess, von dem er aufgerufen wird, dupliziert wird. Der vorhandene Prozess, aus dem diese Funktion aufgerufen wird, wird zum übergeordneten Prozess und der neu erstellte Prozess wird zum untergeordneten Prozess. Wie bereits erwähnt, ist das Kind eine Kopie des Elternteils, es gibt jedoch einige Ausnahmen.

  • Das Kind verfügt über eine eindeutige PID wie jeder andere Prozess, der im Betriebssystem .__ ausgeführt wird.

  • Das untergeordnete Element verfügt über eine übergeordnete Prozess-ID, die der PID von entspricht
    Prozess, der es erstellt hat.

  • Ressourcennutzungs- und CPU-Zeitzähler werden im untergeordneten Prozess

  • Die ausstehenden Signale im Kind sind leer.

  • Child erbt keine Timer von seinem übergeordneten Element

Beispiel:

    #include <unistd.h>
    #include <sys/types.h>
    #include <errno.h>
    #include <stdio.h>
    #include <sys/wait.h>
    #include <stdlib.h>

    int var_glb; /* A global variable*/

int main(void)
{
    pid_t childPID;
    int var_lcl = 0;

    childPID = fork();

    if(childPID >= 0) // fork was successful
    {
        if(childPID == 0) // child process
        {
            var_lcl++;
            var_glb++;
            printf("\n Child Process :: var_lcl = [%d], var_glb[%d]\n", var_lcl, var_glb);
        }
        else //Parent process
        {
            var_lcl = 10;
            var_glb = 20;
            printf("\n Parent process :: var_lcl = [%d], var_glb[%d]\n", var_lcl, var_glb);
        }
    }
    else // fork failed
    {
        printf("\n Fork failed, quitting!!!!!!\n");
        return 1;
    }

    return 0;
}

Nun, wenn der obige Code kompiliert und ausgeführt wird:

$ ./fork

Parent process :: var_lcl = [10], var_glb[20]

Child Process :: var_lcl = [1], var_glb[1]
0
Usman

Die Verwendung von Fork-Systemaufrufen für erstellt einen neuen Prozess, der als untergeordneter Prozess bezeichnet wird und gleichzeitig mit dem Prozess (der als Systemaufrufgabel bezeichnet wird) ausgeführt wird. Dieser Prozess wird als übergeordneter Prozess bezeichnet.

Nachdem ein neuer untergeordneter Prozess erstellt wurde, führen beide Prozesse die nächste Anweisung nach dem Systemaufruf fork () aus. Ein untergeordneter Prozess verwendet denselben PC (Programmzähler), dieselben CPU-Register und dieselben offenen Dateien, die im übergeordneten Prozess verwendet werden.

In einigen Systemen gibt es je nach gewünschtem Verhalten unterschiedliche Versionen von fork ()

Einige UNIX-Systeme haben fork1 () und forkall ()

  • fork1 () dupliziert nur den aufrufenden Thread
  • forkall () dupliziert alle Threads in einem Prozess
0

Fork () - Systemaufruf zum Erstellen eines untergeordneten Prozesses. Es handelt sich um ein exaktes Duplikat des übergeordneten Prozesses. Gabel kopiert Stapelabschnitt, Heapabschnitt, Datenabschnitt, Umgebungsvariable und Befehlszeilenargumente vom übergeordneten Element.

referenz: http://man7.org/linux/man-pages/man2/fork.2.html

0
user9344710