Wie funktioniert das Schlafen eines Fadens?


14

Was ist eigentlich los, wenn du einen Thread schläfst ?

Ich sehe, dass das Schlafen eines Threads "den aktuellen Thread für einen bestimmten Zeitraum pausiert" . Aber wie funktioniert das?

Laut Wie funktioniert Thread.sleep () intern und wie funktioniert Thread.sleep wirklich? ::

  • Die Schlafdauer unterliegt einer gewissen systemspezifischen Granularität
  • Der Schlaf blockiert
  • Der Thread verlässt die CPU und stoppt die Ausführung
  • Der Thread verbraucht im Ruhezustand keine CPU-Zeit

Ich kann die interne und grundlegende Mechanik dessen, was dies alles bedeutet, einfach nicht ganz verstehen.

Ich verstehe, dass es einen sogenannten Scheduler gibt, der für das Wechseln zwischen Threads verantwortlich ist.

Quellen scheinen darauf hinzuweisen, dass dies je nach Betriebssystem (oder Hardware?) Variiert und die meisten Threads 1 ms - 60 ms oder so erhalten, um einige Aktionen auszuführen, bevor die CPU zu einem anderen Thread wechselt.

Aber wenn ein Thread in den Ruhezustand versetzt wird (z. B. viele Sekunden), wie wird er fortgesetzt? Ich vermute, dass ein Timer irgendwie involviert ist. Ist es die Uhr des Motherboards? Bezieht es sich auf die CPU-Taktrate?

Und selbst wenn ein Timer beteiligt ist, woher weiß die CPU, wann es Zeit ist, wieder auf den Thread zu achten? Müsste es nicht ständig im Thread nachsehen, ob es fertig ist? Ist das nicht effektiv Polling und deshalb Art ist raubend CPU - Zeit?

Ist das Schlafen ein Thread sprachspezifisch oder ist das Betriebssystem dafür verantwortlich oder ist es eine CPU-spezifische Sache?

Würde mir das bitte jemand mit grundlegenden Erklärungen zu Dingen wie dem Scheduler und dem, was die CPU während all dem tut, erklären?


2
Das erneute Aufwecken eines schlafenden Threads funktioniert durch zeitgesteuerte Interrupts, die typischerweise durch einen Interrupt-Takt erzeugt werden, bei dem es sich um eine Hardwarekomponente handelt, die vom Kernteil der CPU getrennt ist, der die Anweisungen verarbeitet. Das vermeidet die Notwendigkeit von Abstimmungen. Vielleicht wird diese Erklärung auf Quora einige Dinge klarstellen: quora.com/How-does-threading-work-at-CPU-level
Doc Brown

1
Die meisten JVMs implementieren kein Multithreading: Sie verwenden lediglich die Multithreading-Funktionen des zugrunde liegenden Betriebssystems. Wenn Sie wirklich wissen möchten, wie es funktioniert, gibt es viele Bücher zum Thema Betriebssystemdesign.
Solomon Slow

Antworten:


11

Das Ausführen eines Programms umfasst viel mehr als nur den Code in diesem Programm.

Jedes Programm, das in einem Multiprozess-Betriebssystem ausgeführt wird, unterliegt der Kontrolle des Schedulers des Betriebssystems. Der Scheduler verwaltet eine explizite Tabelle, in der angegeben ist, welcher Prozess ausgeführt wird, welche darauf warten, ausgeführt zu werden, wenn CPU-Zyklen verfügbar sind, und welche nicht gerade sind versuchen zu rennen (schlafen). Der Scheduler weist Prozessen in der Regel Zeitscheiben mit gerader Größe zu, abhängig von ihrer Priorität und ihrem Ausführungsverlauf. Letztendlich wird diese Schleife durch Hardware-Interrupts gesteuert, die normalerweise von einem Oszillator auf der Hauptplatine erzeugt werden.

Sleeping ist immer eine Funktion, die eine Programmiersprache nur unterstützen kann, weil die Laufzeitumgebung, in der sie ausgeführt wird, dies unterstützt. Ein normales Programm kann nicht aussetzen selbst , kann er nur dem Scheduler sagen , wie es würde gerne behandelt werden - und der Planer ist keineswegs verpflichtet , oder sogar immer in der Lage diesen Wunsch zu erfüllen. Stellen Sie sich vor, ein Laptop wird geschlossen und befindet sich im Winterschlaf. Der Oszillator der Hauptplatine pulsiert weiter, aber da der Scheduler nicht läuft, kann auch kein Prozess ausgeführt werden, egal wie hoch seine Priorität ist.


Dies gilt (im Allgemeinen) für Prozesse, jedoch nicht immer für Threads, die manchmal sprachabhängig sind. Threads können unabhängig vom Betriebssystem implementiert werden und kooperativ oder präventiv sein. Zum Beispiel hat Ruby "Fasern" (zusätzlich zu Fäden). Rubinfasern sind kooperativ geplant.
David25272

Richtig, nur native Threads funktionieren so. Grüne Threads werden von der VM geplant, die ein Programm in einer bytekompilierten Sprache ausführt. Normalerweise werden sie verwendet, wenn native Threads nicht verfügbar sind oder wenn Code ausgeführt wird, der nicht ordnungsgemäß threadsicher ist (die VM kann manchmal sicherstellen, dass die Semantik eines Multithread-Programms auf eine Weise korrekt bleibt, die der OS-Scheduler nicht kann).
Kilian Foth

7

Wie Doc Brown in einem Kommentar erwähnt hat, sind Interrupts der Schlüssel und nicht nur zum Schlafen.

Ein Interrupt ist ein Hardware-Signal, dass der Prozessor anhalten und einen Code ausführen soll. Externe Geräte lösen Interrupts aus, wenn sie die Aufmerksamkeit des Prozessors benötigen: Zum Beispiel, wenn eine Festplatte das Lesen von Daten beendet hat oder eine Taste gedrückt wurde oder ein Countdown-Timer auf dem Motherboard Null erreicht hat.

Interrupt-Handling-Code ist im Allgemeinen sehr klein und sehr schnell. Wenn die Festplatte beispielsweise anzeigt, dass ein Block in den Speicher kopiert wurde, zeichnet das Betriebssystem diese Tatsache möglicherweise einfach in einer Liste von "fertigen Blöcken" irgendwo auf und kehrt dann zu dem zurück, was es gerade getan hat. Sie möchten nicht, dass die CPU ihre gesamte Zeit mit Interrupt-Handling-Code verbringt und keinen Benutzercode ausführt.

Ein Teil des Interrupt-gesteuerten Codes, der nicht unbedingt klein ist, ist der Scheduler. Es wird durch ein Signal von einem Countdown-Timer ausgelöst und überprüft den Status des Systems, wann immer es ausgeführt wird. Dies umfasst in der Regel die Identifizierung von Prozessen, die zur Ausführung bereit sind (z. B. weil der Block, auf den sie gewartet haben, im Speicher angekommen ist) sowie von Prozessen, die ihre Zeitscheibe erschöpft haben.

Wenn Sie also einen Thread-Schlaf ausführen, teilen Sie dem Betriebssystem mit, dass (1) Sie Ihre Zeitscheibe aufgeben und (2) Sie erst nach Ablauf einer bestimmten Zeit wieder geweckt werden sollten.

Immer wenn der Scheduler ausgeführt wird, wird Ihr Thread angezeigt und nur dann als "betriebsbereit" markiert, wenn diese Zeit abgelaufen ist. Dies ist eine Art Abfrage, aber keine Abrufschleife, da sie durch einen Interrupt ausgelöst wird. Es ist auch nicht so teuer: Normalerweise laufen nur ungefähr tausend Threads gleichzeitig.

Dies sollte Ihnen auch eine Vorstellung davon geben, warum die Ruhezeiten nicht genau sind: Wenn Ihr Thread zur Ausführung bereit ist, werden möglicherweise andere Threads noch ausgeführt und haben ihre Zeitscheibe nicht ausgeschöpft. Oder es gibt Threads mit höherer Priorität, die zur Ausführung bereit sind.


So funktionieren "moderne" Betriebssysteme. In älteren Betriebssystemen wie Windows 3 oder Mac OS vor OS X musste ein Prozess dem Betriebssystem die Kontrolle geben (). Wenn ein Programm in einer Schleife stecken bleibt oder irgendwie blockiert ist, kann es leider niemals zu einer Kontrolle führen, und das gesamte System würde hängen bleiben.
David25272

@ david25272 - Ich denke, ich würde das Wort "einfacher" anstelle von "älter" verwenden, da es Systeme aus den 1960er Jahren gab, die präventives Multitasking durchführten. Und obwohl es stimmt, dass beim kooperativen Multtasking der aktive Thread etwas tun muss, um die Kontrolle über den Prozessor freizugeben (normalerweise durch einen blockierenden Systemaufruf und nicht durch eine explizite Ausbeute), glaube ich nicht, dass es viele Allzweckprogrammierer gibt heute, die ein Betriebssystem mit einem kooperativen Threading-Modell verwenden.
kdgregory
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.