Thread (computing)

Ein Prozess mit zwei Ausführungsfäden, die auf einem ausgeführt werden Prozessor

Im Informatik, a Faden von Hinrichtung ist die kleinste Abfolge programmierter Anweisungen, die von a unabhängig verwaltet werden können Planer, was normalerweise ein Teil der ist Betriebssystem.[1] Die Implementierung von Threads und Prozesse Unterscheidet sich zwischen Betriebssystemen, aber in den meisten Fällen ist ein Faden ein Bestandteil eines Prozesses. Die mehreren Themen eines bestimmten Prozesses können ausgeführt werden gleichzeitig (über Multithreading -Funktionen), das Teilen von Ressourcen wie z. B. Erinnerung, während verschiedene Prozesse diese Ressourcen nicht teilen. Insbesondere die Threads eines Prozesses teilen seinen ausführbaren Code und die Werte seiner dynamisch zugewiesen Variablen und nichtThread-lokal globale Variablen Zu jeder Zeit.

Geschichte

Themen traten früh unter dem Namen "Aufgaben" in den Namen OS/360 -Multiprogrammierung mit einer variablen Anzahl von Aufgaben (MVT) im Jahr 1967. Salzer (1966) Credits Victor A. Vyssotsky mit dem Begriff "Thread".[2]

Die Popularität des Fadens hat um 2003 zugenommen, da das Wachstum der CPU -Frequenz durch das Wachstum der Anzahl der Kerne ersetzt wurde, wodurch die Verwendung mehrerer Kerne gleichzeitig verwendet werden musste.[3]

Prozesse, Kernel -Threads, Benutzer -Threads und Fasern

Die Planung kann auf Kernelebene oder Benutzerebene erfolgen, und Multitasking kann präventiv oder kooperativ durchgeführt werden. Dies ergibt eine Vielzahl verwandter Konzepte.

Prozesse

Auf Kernelebene a Prozess enthält einen oder mehrere Kernelfäden, die die Ressourcen des Prozesses wie Speicher- und Dateihandles teilen - ein Prozess ist eine Ressourceneinheit, während ein Thread eine Einheit der Planung und Ausführung ist. Die Kernelplanung wird in der Regel präventiv oder, weniger häufig, kooperativ erfolgen. Auf Benutzerebene ein Prozess wie a Laufzeitsystem Kann selbst mehrere Ausführungsfäden planen. Wenn diese keine Daten teilen, wie in Erlang, werden sie normalerweise analog als Prozesse bezeichnet.[4] Während sie Daten teilen, werden sie normalerweise aufgerufen (Benutzer) Threads, insbesondere, wenn auch präventiv geplant. Kooperativ geplante Benutzer -Threads werden als bezeichnet als Fasern; Verschiedene Prozesse können Benutzerfäden unterschiedlich planen. Benutzerfaden können von Kernel-Threads auf verschiedene Weise ausgeführt werden (eins zu eins, viele zu eins, viele zu viel). Der Begriff "Leichter Prozess"Verweist auf Benutzerfäden oder Kernel -Mechanismen zum Planen von Benutzer -Threads auf Kernel -Threads.

A Prozess ist eine "Schwergewichts" -Kernerplanung, da es relativ teuer ist, Prozesse zu erstellen, zu zerstören und zu wechseln. Prozesse eigene Ressourcen vom Betriebssystem zugewiesen. Zu den Ressourcen gehören Speicher (für Code und Daten). Dateigriffe, Sockets, Gerätegriffe, Fenster und a Prozesssteuerungsblock. Prozesse sind isoliert durch Prozessisolationund teilen Sie keine Adressräume oder Dateiressourcen, außer durch explizite Methoden wie Erben von Dateihandles oder gemeinsam genutzten Speichersegmenten oder die gleiche Datei auf gemeinsame Weise zuzuordnen - siehe Interprozesskommunikation. Das Erstellen oder Zerstören eines Prozesses ist relativ teuer, da Ressourcen erworben oder freigegeben werden müssen. Prozesse werden in der Regel präventiv multitaskiert, und die Prozessumschaltung ist relativ teuer, über die grundlegenden Kosten von übereinstimmend Kontextumschaltung, aufgrund von Problemen wie dem Cache -Spülen (insbesondere von Verfahrenswechsel ändert sich virtuelle Speicheradressierung, verursacht Ungültigheit und somit spüle eines nicht getagelten Übersetzungs -Lookaside -Pufferinsbesondere auf x86).

Kernelfäden

EIN Kernelfaden ist eine "leichte" Einheit der Kernelplanung. In jedem Prozess existiert mindestens ein Kernelfaden. Wenn in einem Prozess mehrere Kernel -Threads vorhanden sind, teilen sie dieselben Speicher- und Dateiressourcen. Kernel -Threads werden bei der Prozess des Betriebssystems präventiv multitaskiert Planer ist präventiv. Kernelfäden besitzen keine Ressourcen außer a Stapel, eine Kopie von Register einschließlich der Programm zähler, und Thread-lokaler Speicher (falls vorhanden), und sind daher relativ billig zu schaffen und zu zerstören. Die Thread-Switching ist ebenfalls relativ günstig: Es erfordert einen Kontextschalter (Speichern und Wiederherstellen von Registern und Stapelzeiger), ändert jedoch keinen virtuellen Speicher und ist somit cache-freundlich (TLB gültig bleibt). Der Kernel kann jedem logischen Kern in einem System einen Thread zuweisen (da sich jeder Prozessor in mehrere logische Kerne aufteilt, wenn er Multithreading unterstützt, oder nur einen logischen Kern pro physikalisch blockiert werden. Kernel -Threads dauern jedoch viel länger als Benutzer -Threads ausgetauscht werden.

Benutzerfaden

Themen werden manchmal in implementiert in UserSpace Bibliotheken, so genannt Benutzerfaden. Der Kernel ist sie nicht bewusst, also werden sie verwaltet und geplant in UserSpace. Einige Implementierungen basieren ihre Benutzer -Threads auf mehreren Kernel -Threads, um davon zu profitieren Mehrprozessor Maschinen (M: n Modell). Benutzerfäden wie implementiert von virtuelle Maschinen werden auch genannt grüne Fäden.

Da sind Benutzer -Thread -Implementierungen in der Regel vollständig in UserSpaceDas Kontextwechsel zwischen Benutzer -Threads innerhalb desselben Prozesses ist äußerst effizient, da keine Interaktion mit dem Kernel erforderlich ist Die vom Benutzer Thread oder Faser erforderlichen Register, die ausgeführt werden müssen. Da die Planung im UserSpace stattfindet, kann die Planungsrichtlinie einfacher auf die Anforderungen der Arbeitsbelastung des Programms zugeschnitten werden.

Die Verwendung von Blockierungssystemaufrufen in Benutzer -Threads (im Gegensatz zu Kernel -Threads) kann jedoch problematisch sein. Wenn ein Benutzer -Thread oder eine Glasfaser einen Systemaufruf ausführt, der blockiert, können die anderen Benutzer -Threads und -Fasern im Prozess erst ausgeführt werden, bis der Systemaufruf zurückgegeben wird. Ein typisches Beispiel für dieses Problem ist die Ausführung von E/O: Die meisten Programme werden so geschrieben, dass E/A synchron durchgeführt wird. Wenn ein E/A -Betrieb eingeleitet wird, wird ein Systemanruf getätigt und kehrt erst dann zurück, wenn der E/A -Betrieb abgeschlossen ist. In der Zwischenzeit wird der gesamte Prozess vom Kernel "blockiert" und kann nicht ausgeführt werden, was andere Benutzerfäden und Fasern im selben Prozess durch Ausführung verhungert.

Eine gemeinsame Lösung für dieses Problem (insbesondere von vielen von Green Threads-Implementierungen verwendet) ist eine E/A-API, die eine Schnittstelle implementiert, die den aufrufenden Thread blockiert, anstatt den gesamten Prozess, indem sie nicht blockierende E/A verwendet Intern und eine Planung eines anderen Benutzer -Threads oder einer Faser, während der E/A -Vorgang im Gange ist. Ähnliche Lösungen können für andere Aufrufe von Blockiersystemen bereitgestellt werden. Alternativ kann das Programm geschrieben werden, um die Verwendung von synchronen E/A oder anderen Blockierungssystemaufrufen zu vermeiden (insbesondere mit nicht blockierender E/A, einschließlich Lambda-Kontinuationen und/oder Async/erwarten Primitive[5]).

Fasern

Fasern sind eine noch leichtere Planungseinheit, die sind kooperativ geplant: Eine laufende Faser muss explizit "Ertrag"Damit eine andere Faser ausgeführt werden kann, was ihre Implementierung erheblich erleichtert als Kernel- oder Benutzer -Threads. Eine Faser kann geplant werden, um in einem beliebigen Thread im selben Prozess auszuführen. Dies ermöglicht Anwendungen, um Leistungsverbesserungen zu erzielen, indem sie selbst die Planung selbst verwalten, anstatt zu verlassen, anstatt sie zu verlassen auf dem Kernel Scheduler (der möglicherweise nicht für die Anwendung abgestimmt ist). Parallele Programmierumgebungen wie z. OpenMP Implementieren Sie normalerweise ihre Aufgaben durch Fasern. Eng mit Fasern verwandt sind CoroutinenMit der Unterscheidung, dass Coroutinen ein Konstrukt auf Sprachebene sind, während Fasern ein Konstrukt auf Systemebene sind.

Themen gegen Prozesse

Themen unterscheiden sich von traditionell Multitasking Betriebssystem Prozesse In vielen Wegen:

  • Prozesse sind in der Regel unabhängig, während Threads als Teilmengen eines Prozesses existieren
  • Prozesse tragen erheblich mehr Zustand Informationen als Threads, während mehrere Threads innerhalb eines Prozesses Share -Prozesszustands sowie Erinnerung und andere Ressourcen
  • Prozesse haben getrennt Adressräume, während Threads ihren Adressraum teilen
  • Prozesse interagieren nur über systembereitete Interprozesskommunikation Mechanismen
  • Kontextumschaltung Zwischen den Threads im selben Prozess tritt typischerweise schneller auf als der Kontextwechsel zwischen den Prozessen

Systeme wie Windows NT und OS/2 sollen haben billig Themen und teuer Prozesse; In anderen Betriebssystemen gibt es keinen großen Unterschied, außer bei den Kosten eines Adressraum Schalter, der bei einigen Architekturen (insbesondere bei x86) führt zu a Übersetzungs -Lookaside -Puffer (TLB) Flush.

Die Vor- und Nachteile von Threads vs -Prozessen umfassen:

  • Niedrigerer Ressourcenverbrauch von Threads: Verwenden von Threads kann eine Anwendung mit weniger Ressourcen arbeiten, als sie bei der Verwendung mehrerer Prozesse benötigt wird.
  • Vereinfachte Teilen und Kommunikation von Themen: Im Gegensatz zu Prozessen, die a erfordern Nachrichtenübergang oder gemeinsamer Gedächtnismechanismus zur Durchführung Interprozesskommunikation (IPC), Threads können über Daten, Code und Dateien kommunizieren, die sie bereits teilen.
  • Thread stürzt einen Prozess ab: Aufgrund von Threads, die denselben Adressraum teilen, kann eine illegale Operation, die von einem Thread ausgeführt wird, den gesamten Vorgang zum Absturz bringen. Daher kann ein schlecht benommenes Thread die Verarbeitung aller anderen Threads in der Anwendung stören.

Planung

Präventive gegen kooperative Planung

Betriebssysteme planen auch Threads präventiv oder kooperativ. Multi-User-Betriebssysteme allgemein bevorzugen Präventiver Multithreading für seine feiner körnige Kontrolle über die Ausführungszeit über Kontextumschaltung. Die präventive Planung kann jedoch in Momenten, die von den Programmierern unerwartet sind, kontext-switch-threads Konvoi sperren, Prioritätsinversionoder andere Nebenwirkungen. Im Gegensatz, kooperatives Multithreading stützt sich auf Threads, um die Steuerung der Ausführung aufzugeben und so diese Threads sicherzustellen rennen zur Fertigstellung. Dies kann zu Problemen führen, wenn ein kooperativ multitaskierter Thread Blöcke durch Warten auf a Ressource oder wenn es verhungert Andere Threads, indem sie keine Kontrolle über die Ausführung während der intensiven Berechnung ergeben.

Single-VS-Multi-Proprozessor-Systeme

Bis in die frühen 2000er Jahre hatten die meisten Desktop-Computer nur eine Single-Kern-CPU ohne Unterstützung für Hardware -Threads, obwohl Threads noch auf solchen Computern verwendet wurden, da das Wechsel zwischen Threads im Allgemeinen immer noch schneller war Kontextschalter. In 2002, Intel Unterstützung für Unterstützung für Simultanes Multithreading zum Pentium 4 Prozessor unter dem Namen Hyper-Threading; Im Jahr 2005 stellten sie den Dual-Core vor Pentium d Prozessor und AMD stellte den Dual-Core vor Athlon 64 x2 Prozessor.

Systeme mit einem einzelnen Prozessor implementieren im Allgemeinen Multithreading durch Zeitschneide: das Zentrale Verarbeitungseinheit (CPU) Schalter zwischen verschiedenen Software -Threads. Dies Kontextumschaltung Normalerweise tritt häufig genug auf, dass Benutzer die Threads oder Aufgaben als parallel ausgeführt werden (für beliebte Server-/Desktop-Betriebssysteme, maximale Zeitscheibe eines Threads, wenn andere Threads warten, ist häufig auf 100-200 ms begrenzt). Auf einen Multiprozessor oder Multi-Core System, mehrere Threads können in ausgeführt werden in parallelmit jedem Prozessor oder Kern, der gleichzeitig einen separaten Thread ausführt; auf einem Prozessor oder Kern mit Hardware -Threads, separate Software -Threads können auch gleichzeitig durch separate Hardware -Threads ausgeführt werden.

Fadenmodelle

1: 1 (Fadenstufe auf Kernelebene)

Threads, die vom Benutzer in einer 1: 1 -Korrespondenz mit schedulierbaren Entitäten im Kernel erstellt wurden[6] sind die einfachste mögliche Threading -Implementierung. OS/2 und Win32 benutzte diesen Ansatz von Anfang an, während Linux das GNU C -Bibliothek implementiert diesen Ansatz (über die Nptl oder älter LinuxThreads). Dieser Ansatz wird auch von verwendet Solaris, Netbsd, Freebsd, Mac OS, und iOS.

N: 1 (Threading auf Benutzerebene)

Ein N: 1 Modell impliziert, dass alle Threads auf Anwendungsebene auf eine geplante Entität auf Kernel-Ebene geordnet sind.[6] Der Kernel hat keine Kenntnis der Anwendungs ​​-Threads. Mit diesem Ansatz kann das Kontextumschalter sehr schnell durchgeführt werden und auch auf einfachen Kerneln implementiert werden, die kein Threading unterstützen. Einer der Hauptnachteile ist jedoch, dass er nicht von der Hardwarebeschleunigung profitieren kann Multithread Prozessoren oder Mehrprozessor Computer: Es wird nie mehr als ein Thread gleichzeitig geplant.[6] Zum Beispiel: Wenn einer der Threads eine E/A -Anforderung ausführen muss, wird der gesamte Vorgang blockiert und der Gewindevorteil kann nicht verwendet werden. Das GNU tragbare Threads verwendet Threading auf Benutzerebene, wie es tut Zustandsfäden.

M:N (Hybridfaden)

M:N Karten einige M Anzahl der Anwendungsfäden auf einige N Anzahl der Kernelentitäten,[6] oder "virtuelle Prozessoren". Dies ist ein Kompromiss zwischen Kernelebene ("1: 1") und Benutzerebene ("N: 1 ") Threading. Im Allgemeinen,"M:N"Threading-Systeme sind komplexer als Kernel- oder Benutzer-Threads, da Änderungen an Kernel- und Benutzer-Raum-Code erforderlich sind[Klarstellung erforderlich]. In der M: N -Implementierung ist die Threading -Bibliothek für die Planung von Benutzer -Threads in den verfügbaren Planbaren entsprechend. Dies macht das Kontextwechsel von Threads sehr schnell, da es Systemaufrufe vermeidet. Dies erhöht jedoch die Komplexität und die Wahrscheinlichkeit von Prioritätsinversionsowie suboptimale Planung ohne umfangreiche (und teure) Koordination zwischen dem Userland Scheduler und dem Kernel Scheduler.

Beispiele für Hybridimplementierung

  • Scheduler -Aktivierungen Wird von älteren Versionen der Implementierung der NetBSD nativen Possix -Threads -Bibliothek verwendet (ein M:N Modell im Gegensatz zu einem 1: 1 -Kernel- oder Userspace -Implementierungsmodell)
  • Leichte Prozesse verwendet von älteren Versionen der Solaris Betriebssystem
  • Marcel aus dem PM2 Projekt.
  • Das Betriebssystem für die Tera-Cray MTA-2
  • Das Glasgow Haskell Compiler (GHC) für die Sprache Haskell Verwendet leichte Threads, die auf Betriebssystem -Threads geplant sind.

Geschichte von Fadenmodellen in UNIX -Systemen

Sonnenos 4.x implementiert Leichte Prozesse oder LWPs. Netbsd 2.x+und Libelle BSD Implementieren Sie LWPs als Kernel -Threads (1: 1 -Modell). Sunos 5.2 bis Sunos 5.8 sowie NetBSD 2 bis NETBSD 4 implementierten ein zweistufiges Modell, wodurch ein oder mehrere Threads auf Benutzerebene auf jedem Kernel -Thread (M: n -Modell) multiplexen wurden. Sunos 5.9 und später sowie NetBSD 5 eliminierte Benutzerfäden, die zu einem 1: 1 -Modell zurückkehren.[7] FreeBSD 5 implementiert M: N -Modell. FreeBSD 6 unterstützte sowohl 1: 1 als auch m: n. Benutzer können wählen, welche mit einem bestimmten Programm mit /etc/libmap.conf verwendet werden sollte. Beginnend mit FreeBSD 7 wurde der 1: 1 zum Standard. FreeBSD 8 unterstützt das M: N -Modell nicht mehr.

Single-Thread-VS-Multithread-Programme

Im Computerprogrammierung, Ein-Threading ist die Verarbeitung von einem Befehl zu einer Zeit.[8] In der formalen Analyse der Variablen ' Semantik und Prozesszustand, der Begriff Single Threading kann unterschiedlich verwendet werden, um "Backtracking innerhalb eines einzelnen Fadens" zu bedeuten, was in der üblich ist Funktionelle Programmierung Gemeinschaft.[9]

Multithreading findet sich hauptsächlich in Multitasking -Betriebssystemen. Multithreading ist ein weit verbreitetes Programmier- und Ausführungsmodell, mit dem mehrere Threads im Kontext eines Prozesses existieren können. Diese Themen teilen die Ressourcen des Prozesses, können jedoch unabhängig ausführen. Das Threaded -Programmiermodell bietet Entwicklern eine nützliche Abstraktion der gleichzeitigen Ausführung. Multithreading kann auch auf einen Prozess angewendet werden, um zu aktivieren Parallele Ausführung auf einen Multiprozessierung System.

Multithreading -Bibliotheken liefern in der Regel einen Funktionsaufruf, um einen neuen Thread zu erstellen, der eine Funktion als Parameter nimmt. Anschließend wird ein gleichzeitiger Thread erstellt, mit dem die übergebene Funktion ausgeführt wird und endet, wenn die Funktion zurückkehrt. Die Thread -Bibliotheken bieten auch Datensynchronisationsfunktionen an.

Themen und Datensynchronisation

Themen im gleichen Prozess teilen den gleichen Adressraum. Dies ermöglicht gleichzeitig den Code zu Code zu Paar dicht und bequeme Daten ohne Overhead oder Komplexität von einem austauschen IPC. Wenn sie zwischen den Threads geteilt werden, werden auch einfache Datenstrukturen anfällig für Rennbedingungen Wenn sie mehr als eine CPU -Anweisung benötigen, um zu aktualisieren: Zwei Threads versuchen möglicherweise, die Datenstruktur gleichzeitig zu aktualisieren und sie unerwartet zu finden. Fehler, die durch Rassenbedingungen verursacht werden, können sehr schwer zu reproduzieren und zu isolieren sein.

Um dies zu verhindern, Faden Anwendungsprogrammierschnittstellen (APIS) Angebot Synchronisation Primitive wie zum Beispiel Mutexes zu sperren Datenstrukturen gegen den gleichzeitigen Zugriff. Bei Uniprozessorsystemen muss ein Faden, der in einen verriegelten Mutex läuft, schlafen und somit einen Kontextschalter auslösen. Auf Multi-Processor-Systemen kann der Thread stattdessen den Mutex in a befragen Spinlock. Beide können die Leistung sap und die Prozessoren erzwingen Symmetrische Multiprozessierung (SMP) -Systeme für den Speicherbus, insbesondere wenn die Die Granularität der Verriegelung ist zu fein.

Andere Synchronisations -APIs umfassen Zustandsvariablen, Kritische Abschnitte, Semaphoren, und Monitore.

Fadenpools

Ein beliebtes Programmiermuster mit Threads ist das von Fadenpools wobei beim Start eine festgelegte Anzahl von Threads erstellt wird, die darauf warten, dass eine Aufgabe zugewiesen wird. Wenn eine neue Aufgabe eintrifft, wacht sie auf, erledigt die Aufgabe und geht wieder zum Warten zurück. Dies vermeidet die relativ teuren Funktionen für die Erstellung und Zerstörung von Threads für jede ausgeführte Aufgabe, nimmt das Thread -Management aus der Hand des Anwendungsentwicklers und überlässt sie einer Bibliothek oder dem Betriebssystem, das besser geeignet ist, um das Thread -Management zu optimieren.

Multithread-Programme gegen Single-Thread-Programme Vor- und Nachteile

Multithread-Anwendungen haben die folgenden Vorteile gegenüber Single-Thread-Anträgen:

  • Empfänglichkeit: Multithreading kann es einer Anwendung ermöglichen, auf Eingaben zu reagieren. In einem Ein-Thread-Programm kann die gesamte Anwendung einfrieren, wenn der Hauptausführungs-Thread in einer langjährigen Aufgabe blockiert. Indem Sie so langlebige Aufgaben auf a verschieben Arbeiter Thread Dies ist gleichzeitig mit dem Hauptausführungs -Thread ausgeführt. Es ist möglich, dass die Anwendung auf Benutzereingaben reagiert, während die Aufgaben im Hintergrund ausgeführt werden. Andererseits ist Multithreading in den meisten Fällen nicht die einzige Möglichkeit, ein Programm reaktionsschnell zu halten, mit Nicht blockierende i/o und/oder Unix -Signale verfügbar sein, um ähnliche Ergebnisse zu erzielen.[10]
  • Parallelisierung: Anwendungen, die Multicore- oder Multi-CPU-Systeme verwenden möchten, können Multithreading verwenden, um Daten und Aufgaben in parallele Unteraufgaben zu teilen und die zugrunde liegende Architektur zu verwalten, wie die Threads gleichzeitig auf einem Kern oder parallel auf mehreren Kernen ausgeführt werden. GPU -Computerumgebungen wie CUDA und OpenCL Verwenden Sie das Multithreading -Modell, bei dem Dutzende bis Hunderte von Threads laufen parallel zwischen Daten auf einen große Anzahl von Kernen. Dies ermöglicht wiederum eine bessere Systemauslastung und kann (vorausgesetzt, dass die Synchronisierungskosten die Vorteile nicht erhöhen) eine schnellere Programmausführung bieten kann.

Multithread -Anwendungen haben die folgenden Nachteile:

  • Synchronisation Komplexität und verwandte Fehler: Wenn Sie gemeinsam genutzte Ressourcen verwenden, die für Thread -Programme typisch sind, ist die Programmierer muss vorsichtig sein, um zu vermeiden Rennbedingungen und andere nicht intuitive Verhaltensweisen. Damit Daten korrekt manipuliert werden können, müssen Threads häufig erforderlich Rendezvous in der Zeit, um die Daten in der richtigen Reihenfolge zu verarbeiten. Themen können auch erfordern gegenseitig exklusiv Vorgänge (oft implementiert werden Mutexes) Um zu verhindern, dass gemeinsame Daten in einem Thread gelesen oder überschrieben werden, während sie von einem anderen geändert werden. Unachtsame Verwendung solcher Primitiven können zu führen Deadlocks, Lebensunterhalt oder Rennen über Ressourcen. Wie Edward A. Lee hat geschrieben: "Obwohl Threads ein kleiner Schritt aus der sequentiellen Berechnung zu sein scheinen, stellen sie tatsächlich einen großen Schritt dar. Sie verwerfen die wesentlichen und ansprechendsten Eigenschaften der sequentiellen Berechnung: Verständlichkeit, Vorhersehbarkeit und Determinismus. Threads als Modell von Die Berechnung ist wild nicht deterministisch, und die Aufgabe des Programmierers wird zum Beschneiden dieses Nichtdeterminismus. "[11]
  • Nicht testbar sein. Im Allgemeinen sind Multithread-Programme nicht deterministisch und infolgedessen nicht testbar. Mit anderen Worten, ein Multithread -Programm kann leicht Fehler haben, die sich nie in einem Testsystem manifestieren und sich nur in der Produktion manifestieren.[12][11] Dies kann durch die Einschränkung der Kommunikation zwischen den Threads auf bestimmte gut definierte Muster (z. B. Nachrichten-Passing) gelindert werden.
  • Synchronisationskosten. Als Thread -Kontext -Schalter auf moderne CPUs kann bis zu 1 Million CPU -Zyklen kosten.[13] Es erschwert effiziente Multithreading -Programme. Insbesondere muss besondere Aufmerksamkeit geschenkt werden, um zu vermeiden, dass die Synchronisation zwischen den Threads zu häufig ist.

Programmiersprache Unterstützung

Viele Programmiersprachen unterstützen das Threading in gewisser Weise.

  • IBM Pl/i(F) Unterstützung der Unterstützung für Multithreading (genannt Multitasking) Bereits in den späten 1960er Jahren wurde dies in der optimierenden Compiler und späteren Versionen fortgesetzt. Der IBM Enterprise PL/I Compiler hat eine neue Modell -Thread -API eingeführt. Keine der beiden Versionen war Teil des PL/I -Standards.
  • Viele Implementierungen von C und C ++ Unterstützen Sie das Threading und erhalten Sie Zugriff auf die nativen Threading -APIs des Betriebssystems. Eine standardisierte Schnittstelle für die Thread -Implementierung ist POSIX -Threads (Pthreads), ein Satz von C-Funktionsbibliotheksaufrufen. OS -Anbieter können die Schnittstelle wie gewünscht implementieren. Der Anwendungsentwickler sollte jedoch in der Lage sein, dieselbe Schnittstelle über mehrere Plattformen hinweg zu verwenden. Die meisten Unix Plattformen, einschließlich Linux, unterstützen pthreads. Microsoft Windows hat einen eigenen Satz von Thread -Funktionen in der prozess.h Schnittstelle für Multithreading wie beginthread.
  • Etwas höheres Level (und normalerweise plattformübergreifend) Programmiersprachen wie z. Java, Python, und .NET Framework Sprachen, Threading den Entwicklern aussetzen und die plattformspezifischen Unterschiede bei Threading -Implementierungen in der Laufzeit abstrahieren. Mehrere andere Programmiersprachen und Sprachverlängerungen versuchen auch, das Konzept der Parallelität und des Fadens des Entwicklers vollständig abstrahieren (Cilk, OpenMP, Schnittstelle zur Nachrichtenübergabe (MPI)). Einige Sprachen sind stattdessen für sequentielle Parallelität (insbesondere mit GPUs) ausgelegt, ohne dass Parallelität oder Threads erforderlich sind (ThreadsAteji px, CUDA).
  • Einige interpretierte Programmiersprachen haben Implementierungen (z. B.,, Ruby MRT für Ruby, Cpython für Python), die Threading und Parallelität unterstützen, aber nicht parallele Ausführung von Threads aufgrund von a Global Interpreter Lock (Gil). Das GIL ist eine gegenseitige Ausschlussschloss, die vom Dolmetscher gehalten wird und verhindern kann, dass der Dolmetscher den Anwendungscode gleichzeitig auf zwei oder mehr Threads gleichzeitig interpretiert, was die Parallelität auf mehreren Kernsystemen effektiv einschränkt. Dies begrenzt die Leistung hauptsächlich für prozessorgebundene Threads, für die der Prozessor erforderlich ist, und nicht viel für I/O-gebundene oder netzwerkgebundene. Andere Implementierungen interpretierter Programmiersprachen, wie z. Tcl Vermeiden Sie mit der Thread -Erweiterung die GIL -Grenze, indem Sie ein Apartmentmodell verwenden, bei dem Daten und Code ausdrücklich zwischen Threads "freigegeben" werden müssen. In TCL hat jeder Thread einen oder mehrere Dolmetscher.
  • In Programmiermodellen wie z. CUDA designed für Daten parallele Berechnung, eine Reihe von Threads laufen der gleiche Code Parallel dazu nur mit seiner ID, um seine Daten im Speicher zu finden. Im Wesentlichen muss die Anwendung so gestaltet werden, dass jeder Thread den gleichen Betrieb in verschiedenen Speichersegmenten ausführt, damit er parallel arbeiten und die GPU -Architektur verwenden kann.
  • Hardware -Beschreibung Sprachen wie zum Beispiel Verilog Haben Sie ein anderes Threading -Modell, das eine extrem große Anzahl von Threads unterstützt (für die Modellierung von Hardware).

Siehe auch

Verweise

  1. ^ Lamport, Leslie (September 1979). "So erstellen Sie einen Multiprozessor -Computer, der Multiprocess -Programme korrekt ausführt" (PDF). IEEE -Transaktionen auf Computern. C-28 (9): 690–691. doi:10.1109/tc.1979.1675439. S2CID 5679366.
  2. ^ Salzer, Jerome Howard (Juli 1966). Verkehrskontrolle in einem Multiplex -Computersystem (PDF) (Doktor der Wissenschaftsthese). p. 20.
  3. ^ Sutter, Kraut (März 2005). "Das kostenlose Mittagessen ist vorbei: Eine grundlegende Wende in Richtung Parallelität in der Software". Dr. Dobbs Journal. 30 (3).
  4. ^ "Erlang: 3.1 Prozesse".
  5. ^ Ignatchenko, Sergey. Acht Möglichkeiten, nicht blockierende Rückgaben in Nachrichten-Passing-Programmen zu bewältigen: Von C ++ 98 über C ++ 11 bis C ++ 20. CPPCON. Archiviert vom Original am 2021-11-04.
  6. ^ a b c d Silberschatz, Abraham; Galvin, Peter Baer; Gagne, Greg (2013). Betriebssystemkonzepte (9. Aufl.). Hoboken, N.J.: Wiley. S. 170–171. ISBN 9781118063330.
  7. ^ "Multithreading in der Solaris -Betriebsumgebung" (PDF). 2002. archiviert von das Original (PDF) Am 26. Februar 2009.
  8. ^ Menéndez, Raúl; Lowe, Doug (2001). Murachs CICs für den COBOL -Programmierer. Mike Murach & Associates. p. 512. ISBN 978-1-890774-09-7.
  9. ^ O'hearn, Peter William; Tennent, R. D. (1997). Algolähnliche Sprachen. Vol. 2. Birkhäuser Verlag. p. 157. ISBN 978-0-8176-3937-2.
  10. ^ Ignatchenko, Sergey (August 2010). "Single-Threading: Zurück in die Zukunft?". Überlast. Accu (97): 16–19.
  11. ^ a b Lee, Edward (10. Januar 2006). "Das Problem mit Threads". UC Berkeley.
  12. ^ Ignatchenko, Sergey (August 2015). "Multi-Threading auf geschäftsführender Ebene wird als schädlich angesehen.". Überlast. Accu (128): 4–7.
  13. ^ "No Bugs" Hase (12. September 2016). "Betriebskosten in CPU -Taktzyklen".

Weitere Lektüre

  • David R. Butenhof: Programmierung mit POSIX -Threads, Addison-Wesley, ISBN0-201-63392-2
  • Bradford Nichols, Dick Buttlar, Jacqueline Proulx Farell: PTHREADS -Programmierung, O'Reilly & Associates, ISBN1-56592-115-1
  • Paul Hyde: Java -Thread -Programmierung, Sams, ISBN0-672-31585-8
  • Jim Beveridge, Robert Wiener: Multithreading -Anwendungen in Win32, Addison-Wesley, ISBN0-201-44234-5
  • Uresh Vahalia: Unix -Interna: Die neuen Grenzen, Prentice Hall, ISBN0-13-101908-2