Threads vs (gegabelte) Prozesse

9

Linux-Anwendungen gabeln im Allgemeinen dann exec (mit execve ()), aber Java-Anwendungen und bestimmte Apache-MPMs verwenden Threading. Wenn Forking verwendet, verwendet Fork + Exec, um einen Prozess zu erzeugen. Was ist die High-Level-Version für das Threading? Wie erzeugt JVM oder Worker MPM Threads?

Gregg Leventhal
quelle
2
Schauen Sie sich Stackoverflow an. Dort gibt es mehrere Fragen und Antworten, die einen Teil davon erklärt haben.
Henk Langeveld

Antworten:

13

Die Idee hinter Threads und Prozessen ist ungefähr dieselbe: Sie teilen den Ausführungspfad. Ansonsten unterscheiden sich Threads und Prozesse in Sachen Speicher. Das heißt, Prozesse haben unterschiedlichen VM-Speicherplatz, während Threads alles gemeinsam nutzen, was vor der Aufteilung vorhanden war.

Mit dem Aufruf clone () (man 2 clone) werden sowohl Threading- als auch Forking-Arbeiten zugrunde gelegt:

Im Gegensatz zu fork (2) ermöglicht clone () dem untergeordneten Prozess, Teile seines Ausführungskontexts mit dem aufrufenden Prozess zu teilen, z. B. den Speicherplatz, die Tabelle der Dateideskriptoren und die Tabelle der Signalhandler. (Beachten Sie, dass auf dieser Handbuchseite "Aufrufprozess" normalerweise "übergeordneter Prozess" entspricht. Siehe jedoch die Beschreibung von CLONE_PARENT unten.)

Die Hauptverwendung von clone () besteht darin, Threads zu implementieren: mehrere Steuerungs-Threads in einem Programm, die gleichzeitig in einem gemeinsam genutzten Speicherbereich ausgeführt werden.

Die Unterschiede ergeben sich aus den Flags, die an clone () übergeben werden. Wie Sie auf der Manpage sehen können, sind Fork und Threading nur ein Satz vordefinierter Parameter für clone (). Man kann aber auch benutzerdefinierte Sachen damit machen.

V13
quelle
1
Ähm? Was? Bitte lesen Sie fast jedes Buch zu diesem Thema noch einmal durch, da der separate Speicherplatz für Prozesse eine große Sache ist. Hilft auch dabei, abstürzenden Code zu "fangen", während der Kernel einfach einen Prozess beendet, bei dem ein einzelner Thread durcheinander gerät.
0xC0000022L
3
@ 0xC0000022L Ihr Argument widerspricht nicht der Antwort, wie es mir scheint.
Ruslan
1
@ Ruslan: Ich bin anderer Meinung: "Die Idee [...] ist ungefähr gleich"? Die Idee hinter Threads ist zwar Parallelität, aber für Prozesse ist dies eine ganz andere Geschichte.
0xC0000022L
4
@ 0xC0000022L Sie haben den wichtigen Teil der Antwort von V13 verpasst: "Sie teilen den Ausführungspfad" - die Frage ist, wie Threads erzeugt werden, nicht was der Unterschied zwischen Threads und Prozessen ist
Izkata
@ Izkata: überhaupt nicht. Ich bin nur der Meinung, dass dies keine korrekte Behauptung ist.
0xC0000022L
8

Die meisten Nicht-Unix-Multiprocessing-Betriebssysteme (OSes) verwenden einen "spawn ()" - Aufruf oder ähnliches, um einen neuen Betriebssystemprozess oder Kontrollfluss zu generieren. Spawn () ist in der Regel ein sehr komplexer Aufruf mit vielen Optionen und viel Overhead. Eine der Innovationen von Unix bestand darin, einen viel geringeren Overhead für die Erstellung von Prozessen bereitzustellen - fork (). Unix kümmerte sich um die vielen notwendigen Optionen für spawn (), indem es beliebige Verarbeitungsmengen vor der anderen Hälfte von spawn () mit exec () zuließ.

Da Unix und Varianten davon immer häufiger verwendet wurden, erwies sich die Erstellung von Prozessen mit geringem Overhead als nützlich und wurde verwendet. Tatsächlich wurde es so oft verwendet, dass die Leute noch weniger Aufwand für die Erstellung von Prozessen wollten, und so entstand die Idee von "Threads". Ursprünglich wurden Threads vollständig vom Ursprungsprozess verarbeitet (und Programme wie die JVM können dies mit "grünen Threads" tun). Die Handhabung der Multithread-Planung ist jedoch schwierig und wurde häufig falsch durchgeführt. Es gibt also eine einfachere Zwischenmethode für Threads, bei der das Betriebssystem die Planung übernimmt, aber ein gewisser Overhead gespart wird, indem der Adressraum (normalerweise) zwischen Threads geteilt wird.

Ihre Frage ist schwer zu beantworten, da es verschiedene, aber verwandte Konzepte gibt, die alle "Threads" sind. Für Details benötigen Sie ein Adjektiv, um zu beschreiben, auf welches Sie sich beziehen. Wenn Sie jedoch die Unterschiede verstehen, gelangen Sie wahrscheinlich zu der gewünschten Antwort. Weitere Informationen finden Sie unter "Lightweight-Prozesse", "Benutzer-Threads" und "rfork ()".

mpez0
quelle
1
"Die Handhabung der Multithread-Planung ist schwierig und wurde häufig falsch durchgeführt." Das Implementieren von User-Space-Threads ist kein Problem. Das Problem mit User-Space-Threads besteht darin, dass alle Threads blockiert werden , wenn ein Thread einen blockierenden Systemaufruf ausführt . Die einzige Möglichkeit, dies zu vermeiden, ist die Verwendung von Threads auf Systemebene.
Bakuriu
1
Interessanterweise hat Windows diese Innovation von Unix nicht aufgenommen: Es hat CreateProcess()aber nichts Ähnliches fork().
Ruslan
2
@Bakuriu - Lesen Sie einen der zahlreichen Artikel zum Erstellen von Multiprozessor-Schedulern, zum Aufrechterhalten der Fairness, zum Vermeiden von Hunger, zum Behandeln von Prioritäten usw. Das Implementieren von User-Space-Threads ist, wie Sie sagen, kein Problem. Das Planen nicht trivialer Beispiele ist schwierig.
mpez0
@ Ruslan: Man kann unter Windows gabeln, es ist einfach nicht Teil der Win32-API. Lesen Sie "Die native Windows NT / 2000-API" von Nebbett. Er hat eine Implementierung, die nachahmt fork().
0xC0000022L
3

Threads und Forking sind eigentlich zwei verschiedene Konzepte, die beide in Unix / Linux-Systemen existieren (und beide in C / C ++ verwendet werden können).

Die Idee eines fork () ist (im Grunde genommen) die Erstellung eines separaten Prozesses, der denselben Ausführungscode wie der übergeordnete Prozess hat und dessen Ausführung an der Fork-Zeile beginnt. Der Zweck der Verwendung von Gabeln mit Exec-Funktionen besteht darin, dass Exec-Funktionen den Prozess schließen, der sie beim Beenden aufgerufen hat. Normalerweise geben Sie die PID jedes Prozesses ab (die des Kindes ist immer 0) und lassen das Elternteil warten, bis das Kind die Exec-Funktion ausgeführt hat.

Threads werden für die Parallelität verwendet (denken Sie daran, dass der Elternteil normalerweise in einem gespaltenen Programm auf das Kind wartet). Ein Thread wie pthread in C / C ++ (Google-Suche durchführen) wird parallel zum Hauptprozess ausgeführt und kann globale Variablen und globale Funktionen mit dem ursprünglichen Programm gemeinsam nutzen. Da sich Java-Threads ähnlich verhalten, würde ich mir vorstellen, dass sie sich eher wie diese Threads als wie ein Forking-Prozess verhalten.

Grundsätzlich gibt es einen Unterschied zwischen Gabeln und Gewindeschneiden. Sie machen deutlich unterschiedliche Dinge (obwohl sie ähnlich scheinen). Diese Konzepte können schwer zu verstehen sein, aber Sie können sie durch (umfangreiche) Forschung lernen, wenn Sie den ehrlichen Wunsch haben, sie zu verstehen.

EDIT # 1

In diesen Beispielen erfahren Sie, wie Gabeln und Gewinde aufgerufen und verwendet werden können. Bitte beachten Sie das Verhalten der exec-Funktionen und deren Auswirkungen auf das Hauptprogramm.

http://www.jdembrun.com:4352/computerScience/forkVSthread.zip

jaredad7
quelle
2
Fork (mit oder ohne Exec) kann auch für Parallelität verwendet werden. Ich bin mir nicht sicher, was Sie unter "Exec-Funktionen schließen den Prozess, der sie aufgerufen hat, wenn sie enden" verstehen. Exec ist schon lange fertig, wenn der Prozess endet. Ist auch pthreadeine API, keine Thread-Implementierung.
Mat
Auf der Gabelung zitiere ich meinen OS-Lehrer. Nach dem, was er uns gesagt hat, könnte Forking verwendet werden, um parallel zu laufen, aber wenn es eine Exec-Funktion verwenden würde, wäre dies die letzte. Pthread war als Beispiel gedacht.
Jaredad7
Exec wäre der letzte Aufruf im Code des Aufrufers, nicht die letzte Anweisung des gegabelten Prozesses. Der gegabelte Prozess würde davon leben, den ausgeführten Code auszuführen.
Mat
Ihre Kommentare haben mich veranlasst, diese Dinge zu testen. Ich habe einige C ++ - Programme geschrieben, die das Verhalten von Exec-Funktionen und ihre Auswirkungen auf Programme bei Verwendung in Forks vs. Threads demonstrieren. Bitte beachten Sie die Bearbeitung oben.
Jaredad7
Ich fürchte, die meisten Leute werden sich nicht die Mühe machen, das herunterzuladen. Auch Ihre Beispiele veranschaulichen nicht die interessanten Unterschiede zwischen den Modellen, die hauptsächlich mit dem Teilen (oder Nicht-Teilen) des Adressraums zusammenhängen.
Mat
1

Sowohl die JVM als auch die Apache MPM verlassen sich auf den Kernel für native Threads. Das heißt, sie verwenden das Betriebssystem, um sie zu planen. Natürlich benötigen beide eine eigene API, um den Überblick zu behalten.

Stackoverflow hat bereits mehrere Fragen dazu:

  1. JVM native Threads Besuche diese Antwort für mehr Details.

  2. Apache verfügt über zwei Arten von MPMs: Prefork mit einem Prozess pro Thread und Worker, der mehrere Threads verarbeitet: Apache-MPMs . Überprüfen Sie den Verweis aufcodebucket

Henk Langeveld
quelle
1

Wenn Forking verwendet, verwendet Fork + Exec, um einen Prozess zu erzeugen. Was ist die High-Level-Version für das Threading? Wie erzeugt JVM oder Worker MPM Threads?

Das ist plattformspezifisch, aber unter Linux und ich würde davon ausgehen, dass viele andere POSIX-kompatible Systeme die lokale Implementierung von pthreads verwenden , einer Userland-Threading-API. Z.B:

#include <pthread.h>

pthread_t tid;
pthread_create(&tid, NULL, somefunc, NULL);

Startet einen neuen Thread-Aufruf somefuncals ersten Ausführungspunkt.

Sie können auch Threads erstellen - im Gegensatz zu Gabeln, die denselben globalen Heap- Speicherplatz des übergeordneten Prozesses verwenden, anstatt eine doppelte Kopie davon zu erhalten (beachten Sie jedoch, dass Threads jeweils mit einem eigenen unabhängigen Stapelspeicher ausgeführt werden). mit dem clone()Systemaufruf, auf dem pthreads aufgebaut ist.

Goldlöckchen
quelle