it-swarm.com.de

Welche Ressourcen werden von Threads gemeinsam genutzt?

Vor kurzem wurde mir in einem Interview eine Frage gestellt, was den Unterschied zwischen einem Prozess und einem Thread darstellt. Wirklich, ich wusste die Antwort nicht. Ich dachte kurz nach und gab eine sehr seltsame Antwort. 

Threads haben den gleichen Speicher, Prozesse nicht. Nachdem ich dies beantwortet hatte, lächelte der Interviewer böse und schickte mir folgende Fragen:

F. Kennen Sie die Segmente, in die ein Programm aufgeteilt wird?

Meine Antwort: yep (dachte, es wäre einfach) Stapel, Daten, Code, Heap

F. Also sagen Sie mir: Welche Segmente teilen Threads?

Ich konnte das nicht beantworten und sagte am Ende alle.

Kann mir jemand die richtigen und eindrucksvollen Antworten für den Unterschied zwischen einem Prozess und einem Thread geben?

215
Xinus

Sie sind ziemlich korrekt, aber Threads teilen alle Segmente außer den Stack. Threads verfügen über unabhängige Aufrufstapel. Der Speicher in anderen Threadstapeln ist jedoch immer noch zugänglich. Theoretisch könnten Sie einen Zeiger auf den Speicher im lokalen Stackframe eines anderen Threads halten (obwohl Sie wahrscheinlich einen besseren Platz für diesen Speicher finden sollten!).

145
Greg Hewgill

Aus Wikipedia (Ich denke, das wäre eine wirklich gute Antwort für den Interviewer: P)

Themen unterscheiden sich von traditionellen Multitasking-Betriebssystem Prozesse in dem:

  • prozesse sind normalerweise unabhängig, während Threads als Teilmengen von .__ vorhanden sind. verarbeiten
  • prozesse tragen beträchtliche Zustandsinformationen, während mehrere Threads auch innerhalb eines Prozess-Share-Zustands als Speicher und andere Ressourcen
  • prozesse haben separate Adressräume, während Threads ihre .__ teilen. Adressraum
  • prozesse interagieren nur durch vom System bereitgestellte Interprozesse Kommunikationsmechanismen.
  • Der Kontextwechsel zwischen Threads im selben Prozess ist normalerweise schneller als Kontextwechsel zwischen Prozesse.
48
Jorge Córdoba

Es muss wirklich darauf hingewiesen werden, dass diese Frage zwei Aspekte hat - den theoretischen und den Implementierungsaspekt.

Zuerst betrachten wir den theoretischen Aspekt. Sie müssen verstehen, was ein Prozess konzeptionell ist, um den Unterschied zwischen einem Prozess und einem Thread und dessen Gemeinsamkeiten zu verstehen.

Wir haben folgendes aus Abschnitt 2.2.2 Das klassische Thread-Modell in Modern Operating Systems 3e von Tanenbaum:

Das Prozessmodell basiert auf zwei unabhängigen Konzepten: Ressource Gruppierung und Ausführung. Manchmal ist es nützlich, sie voneinander zu trennen; Hier kommen Fäden ins Spiel .... 

Er fährt fort:

Eine Möglichkeit, einen Prozess zu betrachten, besteht darin, dass es eine Möglichkeit ist, verwandte Ressourcen zusammen. Ein Prozess hat einen Adressraum Programmtext und -daten sowie andere Ressourcen enthalten. Diese Die Ressource kann offene Dateien, untergeordnete Prozesse, anstehende Alarme, .__ enthalten. Signalhandler, Buchhaltungsinformationen und mehr. Indem sie sie setzen. Zusammen in Form eines Prozesses können sie leichter verwaltet werden. Das andere Konzept, das ein Prozess hat, ist ein Ausführungsthread, normalerweise verkürzt, um gerade zu fädeln. Der Thread hat einen Programmzähler, der .__ speichert. verfolgen, welche Anweisung als nächstes ausgeführt werden soll. Es hat Register, die halten seine aktuellen Arbeitsvariablen. Es hat einen Stapel, der die .__ enthält. Ausführungsverlauf mit einem Frame für jede aufgerufene Prozedur, jedoch nicht noch aus zurückgekehrt. Obwohl ein Thread in einem Prozess ausgeführt werden muss, muss der Thread und sein Prozess sind unterschiedliche Konzepte und können behandelt werden separat. Prozesse werden verwendet, um Ressourcen zusammenzufassen. Threads sind die zur Ausführung auf der CPU geplanten Entitäten.

Weiter unten gibt er die folgende Tabelle an:

Per process items             | Per thread items
------------------------------|-----------------
Address space                 | Program counter
Global variables              | Registers
Open files                    | Stack
Child processes               | State
Pending alarms                |
Signals and signal handlers   |
Accounting information        |

Das oben genannte ist, was Sie benötigen, damit Threads funktionieren. Wie andere darauf hingewiesen haben, sind Dinge wie Segmente betriebssystemabhängige Implementierungsdetails.

38

Sagen Sie dem Interviewer, dass dies vollständig von der Implementierung des Betriebssystems abhängt.

Nehmen Sie zum Beispiel Windows x86. Es gibt nur 2 segmente [1], Code und Daten. Beide werden auf den gesamten Adressraum von 2 GB (linear, Benutzer) abgebildet. Basis = 0, Grenze = 2 GB. Sie hätten eine erstellt, aber x86 erlaubt nicht, dass ein Segment sowohl Lesen als auch Schreiben und Ausführen ist. Also machten sie zwei und stellten CS auf den Code-Deskriptor und der Rest (DS, ES, SS usw.) auf den anderen [2]. Aber beide zeigen auf das gleiche Zeug!

Die Person, die Sie interviewt haben, hatte eine versteckte Annahme gemacht, dass sie nicht gesagt hat, und das ist ein dummer Trick.

Also in Bezug auf 

Q. Sagen Sie mir also, welcher Segment-Thread Aktie?

Die Segmente sind für die Frage zumindest unter Windows irrelevant. Threads teilen sich den gesamten Adressraum. Es gibt nur ein Stapelsegment, SS, und es zeigt genau dasselbe wie DS, ES und CS [2]. D.h. der ganze verdammte User Space. 0-2 GB. Das bedeutet natürlich nicht, dass Threads nur einen Stapel haben. Natürlich hat jeder einen eigenen Stack, aber x86-Segmente werden nicht für diesen Zweck verwendet.

Vielleicht macht * nix etwas anderes. Wer weiß. Die Prämisse, auf die sich die Frage stützte, war gebrochen.


  1. Zumindest für den Benutzerplatz.
  2. Von ntsd notepad: cs=001b ss=0023 ds=0023 es=0023
26
Alex Budovski

Im Allgemeinen werden Threads als Leichtgewichtsprozess bezeichnet. Wenn wir Speicher in drei Abschnitte unterteilen, wird dies wie folgt aussehen: Code, data und Stack ..__ Jeder Prozess hat seinen eigenen Code, eigene Daten- und Stack-Abschnitte, und aufgrund dieses Kontextes ist die Umschaltzeit etwas hoch. Um die Kontextwechselzeit zu reduzieren, wurde das Konzept des Threads entwickelt, das das Daten- und Codesegment mit anderen Threads/Prozessen teilt und über ein eigenes STACK-Segment verfügt.

17
Nimish Thakkar

Ein Prozess verfügt über Code-, Daten-, Heap- und Stack-Segmente. Der Instruction Pointer (IP) eines Threads OR 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 der Stapelbereich? Es ist ein Bereich, der vom Prozess nur für den Thread erstellt wird, da der Stack viel schneller als Heaps usw. verwendet werden kann. Der Stackbereich des Prozesses ist zwischen Threads aufgeteilt Der Stapelbereich des Prozesses ist in 3 Teile unterteilt und wird jeweils den 3 Threads zugewiesen. Mit anderen Worten, wenn wir sagen, dass jeder Thread seinen eigenen Stack hat, ist dieser Stack tatsächlich ein Teil des Prozessstapelbereichs, der jedem Thread zugewiesen ist. Wenn ein Thread seine Ausführung abgeschlossen hat, wird der Stack des Threads vom Prozess zurückgefordert. Tatsächlich ist nicht nur der Stack eines Prozesses zwischen Threads aufgeteilt, sondern alle Register, die ein Thread wie SP-, PC- und Statusregister verwendet, sind die Register des Prozesses. Wenn es um das Teilen geht, werden Code-, Daten- und Heap-Bereiche gemeinsam genutzt, während der Stack-Bereich nur unter Threads aufgeteilt wird.

Threads teilen sich den Code und die Datensegmente und den Heap, aber nicht den Stack.

12
Kevin Peterson

Threads teilen Daten und Code, Prozesse dagegen nicht. Der Stapel wird nicht für beide freigegeben.

Prozesse können auch Speicher gemeinsam nutzen, genauer Code, beispielsweise nach einer Fork(). Dies ist jedoch ein Detail der Implementierung und (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, was die genaue Semantik für den Code von Threads ist, aber ich gehe davon aus, dass es sich um Shared Code handelt.

 Prozess-Thread 

 Privat stapeln 
 Daten privat freigegeben 
 Code privat1   geteilt2

1 Der Code ist logically private, kann jedoch aus Leistungsgründen freigegeben werden.2 Ich bin nicht zu 100% sicher.

5

Themen teilen alles [1]. Es gibt einen Adressraum für den gesamten Prozess.

Jeder Thread hat seinen eigenen Stapel und seine eigenen Register, aber die Stapel aller Threads sind im gemeinsam genutzten Adressraum sichtbar.

Wenn ein Thread einem Objekt ein Objekt auf seinem Stack zuordnet und die Adresse an einen anderen Thread sendet, haben beide Zugriff auf dieses Objekt.


Eigentlich ist mir gerade ein breiteres Problem aufgefallen: Ich glaube, Sie verwirren zwei Verwendungen des Wortes segment .

Das Dateiformat für eine ausführbare Datei (z. B. ELF) enthält verschiedene 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 getrennt in den Prozessadressraum mit unterschiedlichen Berechtigungen abgebildet werden (z. B. schreibgeschützte ausführbare Datei für Code/Text und Copy-on-Write nicht ausführbare Datei für initialisierte Daten).

Bereiche dieses Adressraums werden nach Konvention (durch Ihre Sprachlaufzeitbibliotheken erzwungen) für verschiedene Zwecke verwendet, z. B. für die Heap-Zuweisung und Thread-Stacks. Es ist jedoch alles nur Arbeitsspeicher und wahrscheinlich nicht segmentiert, es sei denn, Sie laufen im virtuellen 8086-Modus. Der Stack jedes Threads ist ein Teil des Speichers, der zum Zeitpunkt der Thread-Erstellung zugewiesen wird. Die aktuelle Stack-Top-Adresse wird in einem Stack-Pointer-Register gespeichert, und jeder Thread behält seinen eigenen Stack-Pointer zusammen mit seinen anderen Registern.


[1] OK, ich weiß: Signalmasken, TSS/TSD usw. Der Adressraum, einschließlich aller zugeordneten Programmsegmente, wird jedoch weiterhin gemeinsam genutzt.

4
Useless

In einem x86-Framework können beliebig viele Segmente (bis zu 2 ^ 16-1) geteilt werden. Die ASM-Direktiven SEGMENT/ENDS erlauben 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 zuständig ..__ In vielen Umgebungen sind sogenannte "vereinfachte Segmentdefinitionen" wie .code, .data, .bss,. Stack usw. und abhängig vom "Speichermodell" (klein, groß, kompakt usw.) initialisiert der Loader die Segmentregister entsprechend. Normalerweise werden .data, .bss, .stack und andere übliche Segmente (ich habe das seit 20 Jahren nicht mehr gemacht, daher erinnere ich mich nicht an alle) in einer einzigen Gruppe zusammengefasst - deswegen weisen DS, ES und SS in der Regel darauf hin derselbe Bereich, aber dies dient nur der Vereinfachung.

Im Allgemeinen können alle Segmentregister zur Laufzeit unterschiedliche Werte haben. Die Interviewfrage war also richtig: Welcher der CODE, DATA und STACK wird von Threads gemeinsam verwendet. Heap-Management ist etwas anderes - es ist einfach eine Folge von Aufrufen des Betriebssystems. Was aber, wenn Sie überhaupt kein Betriebssystem haben, wie in einem eingebetteten System. Können Sie trotzdem Code in Ihrem Code neu/löschen?

Mein Rat an die Jugendlichen - lesen Sie ein gutes Programmierbuch. Es scheint, dass die Lehrpläne der Universitäten in dieser Hinsicht ziemlich schlecht sind. 

2
George

Thread teilt den Heap (es gibt eine Recherche über Thread-spezifischen Heap), aber die aktuelle Implementierung teilt den Heap. (und natürlich der Code)

1
Dani

Neben dem globalen Speicher teilen Threads auch eine Reihe anderer Attribute (Das heißt, diese Attribute sind global für einen Prozess und nicht spezifisch für einen Thread.). Diese Attribute umfassen Folgendes:

  • prozess-ID und übergeordnete Prozess-ID;
  • prozessgruppen-ID und Sitzungs-ID;
  • kontrollterminal;
  • anmeldeinformationen verarbeiten (Benutzer- und Gruppen-IDs);
  • offene Dateideskriptoren;
  • datensatzsperren, die mit fcntl(); erstellt wurden
  • signaldispositionen;
  • dateisystem-bezogene Informationen: umask, aktuelles Arbeitsverzeichnis und Stammverzeichnis.
  • intervall-Timer (setitimer()) und POSIX-Timer (timer_create());
  • System V Semaphore Undo (semadj) Werte (Abschnitt 47.8);
  • ressourcengrenzen;
  • Verbrauchte CPU-Zeit (wie von times() zurückgegeben);
  • verbrauchte Ressourcen (wie von getrusage() zurückgegeben); und
  • Netter Wert (eingestellt durch setpriority() und Nice()).

Zu den Attributen, die für jeden Thread unterschiedlich sind, gehört das folgende:

  • thread-ID (Abschnitt 29.5);
  • signalmaske;
  • thread-spezifische Daten (Abschnitt 31.3);
  • alternativer Signalstapel (sigaltstack());
  • die errno-Variable;
  • gleitkomma-Umgebung (siehe fenv(3));
  • echtzeitplanung und -priorität (Abschnitte 35.2 und 35.3);
  • CPU-Affinität (Linux-spezifisch, beschrieben in Abschnitt 35.4);
  • fähigkeiten (Linux-spezifisch, beschrieben in Kapitel 39); und
  • stack (Informationen zu lokalen Variablen und Funktionsaufrufen).

Auszug aus: Die Linux-Programmierschnittstelle: Ein Linux- und UNIX-Systemprogrammierhandbuch, Michael Kerrisk , Seite 619

0
snr

Währenddessen teilen sich alle Threads Systemressourcen wie Heapspeicher usw., während Thread einen eigenen Stack hat

Ihr Ans sollte also Heap-Speicher sein, den alle Threads für einen Prozess gemeinsam nutzen.

0
roshni