Kürzlich wurde mir in einem Interview eine Frage gestellt, was der Unterschied zwischen einem Prozess und einem Thread ist. Wirklich, ich wusste die Antwort nicht. Ich dachte eine Minute nach und gab eine sehr seltsame Antwort.
Threads teilen sich den gleichen Speicher, Prozesse nicht. Nachdem ich darauf geantwortet hatte, schenkte mir der Interviewer ein böses Lächeln und warf mir folgende Fragen zu:
F : Kennen Sie die Segmente , in denen ein Programm geteilt wird?
Meine Antwort: Ja (dachte, es war einfach) Stapel, Daten, Code, Haufen
F. Sagen Sie mir also: Welche Segmente teilen sich Threads?
Ich konnte das nicht beantworten und sagte schließlich alle.
Kann jemand die richtigen und eindrucksvollen Antworten auf den Unterschied zwischen einem Prozess und einem Thread geben?
Antworten:
Sie sind ziemlich korrekt, aber Threads teilen sich alle Segmente außer dem Stapel. Threads haben unabhängige Aufrufstapel, jedoch ist der Speicher in anderen Threadstapeln weiterhin verfügbar, und theoretisch könnten Sie einen Zeiger auf den Speicher im lokalen Stapelrahmen eines anderen Threads halten (obwohl Sie wahrscheinlich einen besseren Platz finden sollten, um diesen Speicher zu platzieren!).
quelle
Aus Wikipedia (Ich denke, das wäre eine wirklich gute Antwort für den Interviewer: P)
quelle
Es muss wirklich darauf hingewiesen werden, dass diese Frage zwei Aspekte hat - den theoretischen Aspekt und den Implementierungsaspekt.
Betrachten wir zunächst den theoretischen Aspekt. Sie müssen verstehen, was ein Prozess konzeptionell ist, um den Unterschied zwischen einem Prozess und einem Thread zu verstehen und was zwischen ihnen geteilt wird.
Wir haben Folgendes aus Abschnitt 2.2.2 Das klassische Gewindemodell in modernen Betriebssystemen 3e von Tanenbaum:
Er fährt fort:
Weiter unten liefert er die folgende Tabelle:
Das Obige ist das, was Sie brauchen, damit Threads funktionieren. Wie andere bereits betont haben, handelt es sich bei Segmenten beispielsweise um betriebssystemabhängige Implementierungsdetails.
quelle
Sagen Sie dem Interviewer, dass dies ausschließlich von der Implementierung des Betriebssystems abhängt.
Nehmen Sie zum Beispiel Windows x86. Es gibt nur 2 Segmente [1], Code und Daten. Und beide sind dem gesamten Adressraum von 2 GB (linear, Benutzer) zugeordnet. Basis = 0, Limit = 2 GB. Sie hätten einen erstellt, aber x86 erlaubt nicht, dass ein Segment sowohl Lesen / Schreiben als auch Ausführen ist. Also machten sie zwei und setzten CS so, dass es auf den Code-Deskriptor zeigt, und den Rest (DS, ES, SS usw.), um auf den anderen zu zeigen [2]. Aber beide zeigen auf das gleiche Zeug!
Die Person, die Sie interviewt hat, hat eine versteckte Annahme gemacht, dass sie nicht angegeben hat, und das ist ein dummer Trick.
Also bezüglich
Die Segmente sind für die Frage zumindest unter Windows irrelevant. Threads teilen sich den gesamten Adressraum. Es gibt nur 1 Stapelsegment, SS, und es zeigt genau dasselbe, was DS, ES und CS tun [2]. Dh der ganze blutige User Space . 0-2 GB. Das bedeutet natürlich nicht, dass Threads nur einen Stapel haben. Natürlich hat jedes seinen eigenen Stapel, aber x86-Segmente werden für diesen Zweck nicht verwendet.
Vielleicht macht * nix etwas anderes. Wer weiß. Die Prämisse, auf der die Frage beruhte, war gebrochen.
ntsd notepad
:cs=001b ss=0023 ds=0023 es=0023
quelle
Im Allgemeinen werden Fäden als leichter Prozess bezeichnet. Wenn wir den Speicher in drei Abschnitte unterteilen, ist dies: Code, Daten und Stapel. Jeder Prozess hat seine eigenen Code-, Daten- und Stapelabschnitte und aufgrund dieses Kontexts ist die Umschaltzeit etwas hoch. Um die Kontextwechselzeit zu verkürzen, haben die Benutzer ein Thread-Konzept entwickelt, das Daten- und Codesegmente mit anderen Threads / Prozessen teilt und über ein eigenes STACK-Segment verfügt.
quelle
Ein Prozess hat Code-, Daten-, Heap- und Stapelsegmente. Der Instruction Pointer (IP) eines Threads ODER eines Threads zeigt nun auf das Codesegment des Prozesses. Die Daten- und Heap-Segmente werden von allen Threads gemeinsam genutzt. Was ist nun mit dem Stapelbereich? Was ist eigentlich die Stapelfläche? Es ist ein Bereich, der vom Prozess nur für die Verwendung durch seinen Thread erstellt wurde ... da Stapel viel schneller als Heaps usw. verwendet werden können. Der Stapelbereich des Prozesses wird auf Threads aufgeteilt, dh wenn 3 Threads vorhanden sind, dann die Der Stapelbereich des Prozesses ist in 3 Teile unterteilt und jeweils den 3 Fäden zugeordnet. Mit anderen Worten, wenn wir sagen, dass jeder Thread seinen eigenen Stapel hat, ist dieser Stapel tatsächlich ein Teil des Prozessstapelbereichs, der jedem Thread zugewiesen ist. Wenn ein Thread seine Ausführung beendet hat, wird der Stapel des Threads vom Prozess zurückgefordert. Eigentlich, Nicht nur der Stapel eines Prozesses wird auf Threads aufgeteilt, sondern alle Register, die ein Thread wie SP-, PC- und Statusregister verwendet, sind die Register des Prozesses. Wenn es um die Freigabe geht, werden Code-, Daten- und Heap-Bereiche gemeinsam genutzt, während der Stapelbereich nur auf Threads aufgeteilt wird.
quelle
Threads teilen sich die Code- und Datensegmente und den Heap, aber nicht den Stapel.
quelle
Threads teilen Daten und Code, Prozesse hingegen nicht. Der Stapel wird nicht für beide freigegeben.
Prozesse können auch Speicher gemeinsam nutzen, genauer gesagt Code, beispielsweise nach a
Fork()
. Dies ist jedoch ein Implementierungsdetail und eine (Betriebssystem-) Optimierung. Code, der von mehreren Prozessen gemeinsam genutzt wird, wird (hoffentlich) beim ersten Schreiben in den Code dupliziert - dies wird als Copy-on-Write bezeichnet . Ich bin mir nicht sicher über die genaue Semantik für den Code von Threads, aber ich gehe von gemeinsam genutztem Code aus.1 Der Code ist logisch privat, kann jedoch aus Leistungsgründen freigegeben werden. 2 Ich bin nicht 100% sicher.
quelle
Threads teilen alles [1]. Es gibt einen Adressraum für den gesamten Prozess.
Jeder Thread hat seinen eigenen Stapel und seine eigenen Register, aber alle Stapel der Threads sind im gemeinsam genutzten Adressraum sichtbar.
Wenn ein Thread ein Objekt auf seinem Stapel zuweist und die Adresse an einen anderen Thread sendet, haben beide den gleichen Zugriff auf dieses Objekt.
Eigentlich ist mir gerade ein größeres Problem aufgefallen: Ich denke, Sie verwechseln zwei Verwendungen des Wortsegments .
Das Dateiformat für eine ausführbare Datei (z. B. ELF) enthält unterschiedliche Abschnitte, die als Segmente bezeichnet werden können und kompilierten Code (Text), initialisierte Daten, Linkersymbole, Debug-Informationen usw. enthalten. Es gibt keine Heap- oder Stapelsegmente hier, da dies nur Laufzeitkonstrukte sind.
Diese binären Dateisegmente können separat mit unterschiedlichen Berechtigungen in den Prozessadressraum abgebildet werden (z. B. schreibgeschützt ausführbar für Code / Text und nicht ausführbar kopierbar beim Schreiben für initialisierte Daten).
Bereiche dieses Adressraums werden gemäß Konvention (von Ihren Sprachlaufzeitbibliotheken erzwungen) für verschiedene Zwecke verwendet, z. B. Heap-Zuweisung und Thread-Stapel. Es ist jedoch alles nur Speicher und wahrscheinlich nicht segmentiert, es sei denn, Sie arbeiten im virtuellen 8086-Modus. Der Stapel jedes Threads ist ein Speicherblock, der zum Zeitpunkt der Thread-Erstellung zugewiesen wird, wobei die aktuelle Stapeloberadresse in einem Stapelzeigerregister gespeichert ist und jeder Thread seinen eigenen Stapelzeiger zusammen mit seinen anderen Registern behält.
[1] OK, ich weiß: Signalmasken, TSS / TSD usw. Der Adressraum einschließlich aller zugeordneten Programmsegmente wird jedoch weiterhin gemeinsam genutzt.
quelle
In einem x86-Framework kann man so viele Segmente teilen (bis zu 2 ^ 16-1). Die ASM-Direktiven SEGMENT / ENDS ermöglichen dies, und die Operatoren SEG und OFFSET ermöglichen die Initialisierung von Segmentregistern. CS: IP werden normalerweise vom Loader initialisiert, aber für DS, ES, SS ist die Anwendung für die Initialisierung verantwortlich. In vielen Umgebungen sind sogenannte "vereinfachte Segmentdefinitionen" wie .code, .data, .bss, .stack usw. zulässig, und je nach "Speichermodell" (klein, groß, kompakt usw.) initialisiert der Loader Segmentregister entsprechend. Normalerweise werden .data, .bss, .stack und andere übliche Segmente (ich habe dies seit 20 Jahren nicht mehr getan, daher erinnere ich mich nicht an alle) in einer einzigen Gruppe zusammengefasst - deshalb zeigen normalerweise DS, ES und SS auf die gleicher Bereich, aber dies dient nur der Vereinfachung.
Im Allgemeinen können alle Segmentregister zur Laufzeit unterschiedliche Werte haben. Die Interviewfrage war also richtig: Welche der CODE, DATA und STACK werden von den Threads gemeinsam genutzt. Heap-Management ist etwas anderes - es ist einfach eine Folge von Aufrufen des Betriebssystems. Aber was ist, wenn Sie überhaupt kein Betriebssystem haben, wie in einem eingebetteten System - können Sie immer noch Neues / Löschen in Ihrem Code haben?
Mein Rat an die jungen Leute - lesen Sie ein gutes Assembler-Programmierbuch. Es scheint, dass die Lehrpläne der Universitäten in dieser Hinsicht ziemlich schlecht sind.
quelle
Auszug aus: Die Linux-Programmierschnittstelle: Ein Handbuch zur Linux- und UNIX-Systemprogrammierung, Michael Kerrisk , Seite 619
quelle
Thread teilen den Heap (es gibt eine Untersuchung über threadspezifische Heap), aber die aktuelle Implementierung teilt den Heap. (und natürlich den Code)
quelle
Während des Prozesses teilen sich alle Threads Systemressourcen wie Heapspeicher usw., während Thread einen eigenen Stapel hat
Ihre Ans sollte also Heap-Speicher sein, den alle Threads für einen Prozess gemeinsam nutzen.
quelle