GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Einführung in Linux-Threads – Teil I

Ein Ausführungs-Thread wird oft als die kleinste Verarbeitungseinheit angesehen, an der ein Planer arbeitet.

Ein Prozess kann mehrere Ausführungs-Threads haben, die asynchron ausgeführt werden.

Diese asynchrone Ausführung bringt die Fähigkeit jedes Threads mit sich, eine bestimmte Arbeit oder einen bestimmten Dienst unabhängig zu handhaben. Daher führen mehrere Threads, die in einem Prozess ausgeführt werden, ihre Dienste aus, was insgesamt die vollständige Fähigkeit des Prozesses darstellt.

In diesem Artikel werden wir die Grundlagen von Threads ansprechen und das grundlegende Verständnis aufbauen, das zum Erlernen der Praxis erforderlich ist Aspekte von Linux-Threads.

Linux Threads Series:Teil 1 (dieser Artikel), Teil 2, Teil 3.

Warum Threads erforderlich sind?

Nun würde man fragen, warum brauchen wir mehrere Threads in einem Prozess? Warum kann nicht in jeder Situation ein Prozess mit nur einem (Standard-)Hauptthread verwendet werden.

Nun, um dies zu beantworten, betrachten wir ein Beispiel:

Angenommen, es gibt einen Prozess, der Echtzeiteingaben empfängt und entsprechend jeder Eingabe eine bestimmte Ausgabe erzeugen muss. Wenn nun der Prozess nicht multithreaded ist, dh wenn der Prozess nicht mehrere Threads umfasst, dann wird die gesamte Verarbeitung in dem Prozess synchron. Das bedeutet, dass der Prozess eine Eingabe verarbeitet und eine Ausgabe erzeugt.

Die Einschränkung im obigen Design besteht darin, dass der Prozess eine Eingabe nicht akzeptieren kann, bis die Verarbeitung der früheren Eingabe abgeschlossen ist, und falls die Verarbeitung einer Eingabe länger als erwartet dauert, wird das Akzeptieren weiterer Eingaben ausgesetzt.

Um die Auswirkungen der obigen Einschränkung zu berücksichtigen, wenn wir das obige allgemeine Beispiel einem Socket-Serverprozess zuordnen, der Eingabeverbindungen akzeptieren kann, diese verarbeiten und dem Socket-Client eine Ausgabe bereitstellen. Wenn nun der Serverprozess bei der Verarbeitung einer Eingabe länger als erwartet dauert und in der Zwischenzeit eine andere Eingabe (Verbindungsanforderung) an den Socket-Server geht, dann könnte der Serverprozess die neue Eingabeverbindung nicht akzeptieren, da sie bereits feststeckt Verarbeitung der alten Eingangsverbindung. Dies kann zu einem Verbindungs-Timeout beim Socket-Client führen, der gar nicht erwünscht ist.

Dies zeigt, dass das synchrone Ausführungsmodell nicht überall angewendet werden kann, und daher wurde die Forderung nach einem asynchronen Ausführungsmodell festgestellt, das durch die Verwendung von Threads implementiert wird.

Unterschied zwischen Threads und Prozessen

Im Folgenden sind einige der Hauptunterschiede zwischen dem Thread und den Prozessen aufgeführt:

  • Prozesse teilen ihren Adressraum nicht, während Threads, die unter demselben Prozess ausgeführt werden, den Adressraum teilen.
  • Aus dem obigen Punkt wird deutlich, dass Prozesse unabhängig voneinander ausgeführt werden und die Synchronisation zwischen Prozessen nur vom Kernel übernommen wird, während andererseits die Thread-Synchronisation von dem Prozess übernommen werden muss, unter dem die Threads ausgeführt werden
  • Der Kontextwechsel zwischen Threads ist schnell im Vergleich zum Kontextwechsel zwischen Prozessen
  • Die Interaktion zwischen zwei Prozessen wird nur durch die Standardkommunikation zwischen Prozessen erreicht, während Threads, die unter demselben Prozess ausgeführt werden, leicht kommunizieren können, da sie die meisten Ressourcen wie Speicher, Textsegment usw. gemeinsam nutzen

Benutzer-Threads vs. Kernel-Threads

Threads können sowohl im Userspace als auch im Kernelspace existieren.

Ein Benutzerbereich Threads werden mit Hilfe von Userspace-Thread-Bibliotheken erstellt, kontrolliert und zerstört. Diese Threads sind dem Kernel nicht bekannt und daher ist der Kernel nirgendwo an ihrer Verarbeitung beteiligt. Diese Threads folgen dem kooperativen Multitasking, bei dem ein Thread die CPU auf eigenen Wunsch freigibt, dh der Scheduler kann den Thread nicht vorbelegen. Der Vorteil von Userspace-Threads besteht darin, dass das Umschalten zwischen zwei Threads nicht viel Overhead mit sich bringt und im Allgemeinen sehr schnell ist, während es auf der negativen Seite ist, da diese Threads dem kooperativen Multitasking folgen. Wenn also ein Thread blockiert wird, wird der gesamte Prozess blockiert. P>

Ein Kernel-Space Thread wird vom Kernel erstellt, kontrolliert und zerstört. Für jeden Thread, der im User Space existiert, gibt es einen entsprechenden Kernel-Thread. Da diese Threads vom Kernel verwaltet werden, folgen sie dem preemptiven Multitasking, bei dem der Scheduler einen Thread in der Ausführung mit einem Thread mit höherer Priorität, der zur Ausführung bereit ist, vorbelegen kann. Der Hauptvorteil von Kernel-Threads besteht darin, dass selbst wenn einer der Threads blockiert wird, der gesamte Prozess nicht blockiert wird, da Kernel-Threads der präemptiven Planung folgen, während auf der negativen Seite der Kontextwechsel im Vergleich zu User-Space-Threads nicht sehr schnell ist.

Wenn wir von Linux sprechen, dann sind Kernel-Threads so weit optimiert, dass sie als besser als User-Space-Threads gelten und meistens in allen Szenarien verwendet werden, außer wenn die Hauptanforderung kooperatives Multitasking ist.

Problem mit Threads

Es gibt einige große Probleme, die bei der Verwendung von Threads auftreten:

  • Viele Betriebssysteme implementieren Threads nicht als Prozesse, sondern sehen Threads als Teil eines übergeordneten Prozesses. Was würde in diesem Fall passieren, wenn ein Thread fork() aufruft, oder noch schlimmer, was, wenn ein Thread eine neue Binärdatei ausführt? Diese Szenarien können gefährliche Folgen haben, zum Beispiel in dem späteren Problem, dass der gesamte übergeordnete Prozess durch den Adressraum der neu ausgeführten Binärdatei ersetzt werden könnte. Dies ist keineswegs erwünscht. Linux, das eine POSIX-Beschwerde ist, stellt sicher, dass das Aufrufen einer fork() nur den Thread dupliziert, der die fork()-Funktion aufgerufen hat, während eine Ausführung von einem der Threads alle Threads im übergeordneten Prozess stoppen würde.
  • Ein weiteres Problem, das auftreten kann, sind Parallelitätsprobleme. Da Threads alle Segmente gemeinsam nutzen (mit Ausnahme des Stack-Segments) und jederzeit vom Scheduler vorbelegt werden können, könnte jede globale Variable oder Datenstruktur, die durch Vorbelegung eines Threads in einem inkonsistenten Zustand gelassen werden kann, schwerwiegende Probleme verursachen, wenn die nächste hohe Priorität erreicht wird Thread führt dieselbe Funktion aus und verwendet dieselben Variablen oder Datenstrukturen.

Zum oben erwähnten Problem 1 können wir nur sagen, dass es sich um ein Designproblem handelt und das Design für Anwendungen so erfolgen sollte, dass möglichst wenig Probleme dieser Art auftreten.

Für das oben erwähnte Problem 2 kann der Programmierer mithilfe von Sperrmechanismen einen Codeabschnitt innerhalb einer Funktion sperren, sodass selbst bei einem Kontextwechsel (wenn die globale Variable und die Datenstrukturen der Funktion in einem inkonsistenten Zustand waren) der nächste Thread dies nicht kann Führen Sie denselben Code aus, bis der gesperrte Codeblock innerhalb der Funktion vom vorherigen Thread (oder dem Thread, der ihn erworben hat) entsperrt wird.


Linux
  1. Einführung in Nmap unter Kali Linux

  2. Grundlagen zu Linux-Signalen – Teil I

  3. Einführung in die Grundlagen des IP-Routings unter Linux (Teil 1)

  4. Maximale Anzahl von Threads pro Prozess in Linux?

  5. Sind Linux-Kernel-Threads wirklich Kernel-Prozesse?

Beispiele für Linux-Curl-Befehle – Teil 2

So beenden Sie einen Prozess in Linux

Pstree-Befehl unter Linux

Kill-Befehl unter Linux

Eine Einführung in den Vivaldi-Browser unter Linux

Prozessüberwachung unter Linux