Kann Multithreading auf einem Einzelprozessorsystem implementiert werden?

74

Ich bin immer dem Konzept gefolgt, dass Multithreading nur auf Systemen mit mehreren Prozessoren implementiert werden kann, auf denen jedem Thread mehr als ein Prozessor zugewiesen werden kann und jeder Thread gleichzeitig ausgeführt werden kann. In diesem Fall gibt es keine Zeitplanung, da jedem Thread separate Ressourcen zugewiesen sind. Aber ich habe es immer wieder irgendwo gelesen, dass ich Multithreading auch auf Einzelprozessorsystemen durchführen kann. Ist es richtig? und wenn ja, was ist dann der Unterschied zwischen Einzelprozessor- und Mehrprozessorsystemen?

Ayse
quelle
9
Ja, und einfach ausgedrückt, wahrgenommene oder tatsächliche Parallelität.
WhozCraig
9
Wenn es nicht möglich war, war Windows 95 eine Massenhalluzination. (Wenn Sie Multiprocessing als Multithreading zählen, war das ursprüngliche Unix auch eine Massenhalluzination.)
Raymond Chen
[link] ( qnx.com/developers/docs/qnxcar2/… ) Bilder, die mächtiger sind als Worte
LinconFive

Antworten:

71

Natürlich kann dies auf einem Einzelprozessorsystem durchgeführt werden, und tatsächlich ist es auf diese Weise viel einfacher. Es funktioniert genauso wie das Ausführen mehrerer Prozesse - der Kernel setzt über einen Timer-Interrupt oder einen ähnlichen Mechanismus einen aus, speichert seinen Maschinenzustand und ersetzt diesen durch den zuvor gespeicherten Zustand eines anderen - der einzige Unterschied besteht darin, dass zwei Threads desselben Prozesses teilen sich denselben virtuellen Speicherplatz, wodurch der Taskwechsel wesentlich effizienter wird.

Multithreading auf Multiprozessorsystemen ist tatsächlich viel schwieriger, da Sie Probleme beim gleichzeitigen Zugriff auf den Speicher von mehreren CPUs / Kernen haben und all die unangenehmen Probleme bei der Speichersynchronisierung, die sich daraus ergeben.

R .. GitHub HÖREN SIE AUF, EIS ZU HELFEN
quelle
Ich danke dir sehr. Das war hilfreich
Ayse
4
Nein, Sie müssen das falsch verstehen, weil die Aussage, wie Sie sie umschrieben haben, definitiv falsch ist.
R .. GitHub STOP HELPING ICE
3
⁺¹ für den «Timer Interrupt». Im gesamten Internet wird nicht erwähnt, wie genau der Wechsel in der Hardware erfolgt. Ich nahm an, es ist eine Art Timer, aber selbst die Wikipedia schweigt.
Hi-Angel
Wenn 2 Threads auf einem Prozessor ausgeführt werden ... ist keine Synchronisierung erforderlich?
Ich habe die Antwort von @Barath Post erhalten.
73

Ich habe es kürzlich irgendwo gelesen, dass ich Multithreading auch auf Einzelprozessorsystemen durchführen kann. Ist es richtig? und wenn ja, was ist dann der Unterschied zwischen Einzelprozessor- und Mehrprozessorsystemen?

Ja, Sie können Multithreading auf einem einzelnen Prozessorsystem ausführen.

In einem Multiprozessorsystem werden mehrere Threads gleichzeitig auf verschiedenen Kernen ausgeführt. Beispiel: Wenn zwei Threads und zwei Kerne vorhanden sind, wird jeder Thread auf einem einzelnen Kern ausgeführt.

In einem Einzelprozessorsystem werden mehrere Threads nacheinander ausgeführt oder warten, bis ein Thread beendet ist oder vom Betriebssystem vorbelegt wird, abhängig von der Thread-Priorität und der Betriebssystemrichtlinie. Die ausgeführten Threads geben jedoch die Illusion, dass sie gleichzeitig ausgeführt werden , relativ zur erforderlichen Anwendungsantwortzeit der User Space-Anwendung.

Zeitvergleich (Beispiel):

Wenn zwei Threads jeweils 10us benötigen, um ausgeführt zu werden, beträgt die Nettozeit auf einem 2-Prozessor-System 10us

Wenn zwei Threads jeweils 10us benötigen, um ausgeführt zu werden, beträgt die Nettozeit auf einem 1-Prozessor-System 20us

Barath Ravikumar
quelle
2
sehr hilfreich. Vielen Dank :)
Ayse
9
Chrome führt Registerkarten in Prozessen aus , nicht in Threads. Die Behauptung, dass Gewinde die Stabilität verbessern, ist falsch. Es ist nicht möglich, dass ein Thread abstürzt und der Rest läuft. Da alle Threads eines Prozesses einen gemeinsamen Adressraum haben, sind sie möglicherweise alle von einem Thread-Clobbering-Speicher betroffen. Darüber hinaus beendet eine unfreiwillige Beendigung, die durch ein "Abstürzen" eines Threads verursacht wird, den gesamten Prozess, nicht nur einen einzelnen Thread.
R .. GitHub STOP HELPING ICE
1
@R .. Ok, ich habe den umstrittenen Teil entfernt .... vielleicht habe ich nicht genug gelesen, um die Stabilität von Threads zu sichern und zu rechtfertigen ...
Barath Ravikumar
Der einzige Weg, wie ich ein Argument sehen kann, dass Threads "die Stabilität verbessern", besteht darin, den Code zu vereinfachen und Fehler weniger wahrscheinlich zu machen. Es ist viel einfacher, synchrone Logik zu schreiben, die in einem eigenen Thread ausgeführt wird, als asynchrone, ereignisgesteuerte Zustandsmaschinenlogik, und dies könnte zu sichereren, stabileren Programmen führen. Threads geben Ihnen jedoch keine Sicherheit, wenn einer von ihnen UB aufruft.
R .. GitHub STOP HELPING ICE
4
Ich denke, BarathBushans Antwort ist hepful und die Leute sollten es vermeiden, darüber abzustimmen :(
Ayse
12

Sie können mehr als vier aktive Threads in einem Quad-Core-System haben. Es gibt eine Zeitplanung, es sei denn, Sie können garantieren, dass Prozesse nicht versuchen, mehr Threads zu erstellen als Prozessoren.

Ja, Sie können mehrere Threads auf einem Single-Core-Computer haben.

Der Unterschied zwischen Einzelprozessor- und Multiprozessorsystemen besteht darin, dass ein Multiprozessorsystem tatsächlich mehr als eine Sache gleichzeitig ausführen kann. Es kann N Dinge gleichzeitig tun, wobei N die Anzahl der Prozessorkerne ist. Ein Einzelprozessorkern kann jeweils nur eine Aufgabe ausführen. Wie WhozCraig in seinem Kommentar sagte, ist es der Unterschied zwischen tatsächlicher und wahrgenommener Parallelität.

Jim Mischel
quelle
Vielen Dank, ich habe jetzt die Grundidee, wie die Dinge gemacht werden
Ayse
5

Ja, das kannst du total. Vor langer Zeit (Win 95?) Sind wir vom kooperativen Multitasking zum Multithreading übergegangen, weil immer jemand den kooperativen Teil vermasselt hat. Jedes Programm auf Ihrem Computer hat mindestens einen Thread. Möglicherweise mehr. Und die CPU wechselt immer wieder ein paar Millionen Mal pro Sekunde zwischen all diesen Threads. Wenn keiner von ihnen etwas zu tun hat, kann es sogar für einige Zeit inaktiv werden.

Multicore-Systeme bedeuten nur, dass zwei oder mehr dieser Threads parallel ausgeführt werden.

Es bringt Ihnen jedoch viel weniger dazu. Mit Multithreading auf einem Single Core-Computer können Sie lediglich Multitasking simulieren.

Mulitasking reicht aus, um zu verhindern, dass der GUI-Thread aufgrund eines langwierigen Vorgangs blockiert. Die Implementierung ist jedoch im Allgemeinen kompliziert, es sei denn, Sie haben Hilfe vom Compiler oder Langauge (wie C # async ... warten). Infolgedessen verwendeten viele GUI-Programmierer nur Multithreading und Invoking, um Multitasking zu fälschen. Wenn dieser Code auf einem oder mehreren Kernen ausgeführt wird, spielt dies keine Rolle.

Am wichtigsten ist, dass Multitasking NICHT für CPU-gebundene Operationen geeignet ist. 95% aller Async-Probleme sind jedoch nicht an die CPU gebunden. Sie sind netzwerk- oder festplattengebunden. Auf einem Singlecore-Computer hilft Multithreading auch nicht bei CPU-gebundenen Dingen. Wenn Sie zwei Threads haben, die beide 100% CPU-Zeit benötigen (dasselbe Programm oder ein anderes), aber nur einen Kern, um sie auszuführen, muss die CPU nur zwischen der Ausführung beider Threads mit 49% wechseln und die verbleibenden 2% für alle verwenden andere Threads, die nur wenig tun.

Schließlich können nur sehr wenige Probleme tatsächlich mit Multithreading behandelt werden. Versuchen Sie einfach, die Fibonacci-Sequenz (ein Thread für jedes Paar) zu multithreaden, ohne sie langsamer, speicherintensiver und komplexer zu machen.

tl; dr; Sie benötigen Multithreading und einen Multicore-Computer für CPU-gebundene Probleme. Die meisten asynchronen Probleme sind nicht an die CPU gebunden. Multitasking ist weit genug. Und Sie können mithilfe von Threads auch auf einem Single-Core-Computer Multitasking durchführen.

Christopher
quelle
4

Hier ist ein sehr vereinfachtes Beispiel. Es ist eigentlich ein Prototyp für ein Programm, das ich erstelle. Es ist eine Implementierung von kooperativem Multitasking in einem einzigen Thread.

mainsetzt einfach das quitFlag auf false, füllt ein Array von Funktionszeigern (die Aufgaben) und ruft dann auf loop.

loopVerwendungen setjmpeinen Rückkehrpunkt für einen nicht-lokalen Sprung (einen Sprung einzustellen aus der Funktion zurück zu einer vorherigen Position in der Ausführung) , und dann gehen die erste Aufgabe (Funktion) zu nennen.

Jede Aufgabe endet mit yield(). Das heißt, keine der Aufgaben funktioniert tatsächlich return. Sie enthalten nicht nur keine return;Anweisung (was in Ordnung wäre, da es sich um voidFunktionen handelt, dh Prozeduren), sondern sie würden returnauch dann nicht die Anweisung erreichen , wenn sie vorhanden wäre, da yieldsie zum setjmpAufruf zurückspringen und diesmal eine 1 für die ifAnweisung ergeben in loop. Die von der Anweisung gesteuerte ifAnweisung wählt eine andere Aufgabe aus, bevor sie erneut in die whileSchleife eintritt .

Daher wird jede Aufgabenfunktion mehrmals ausgeführt, was dem Dispatcher (der if(setjmp...Anweisung) ergibt, der eine neue auszuführende Aufgabe auswählt.

#include <stdio.h> 
#include <setjmp.h> 

jmp_buf dispatch; 
int ntasks; 
void (*task[10])(void); 
int quit; 

void yield(void) { 
    longjmp(dispatch, 1); 
} 

void loop() { 
    static int i = 0; 
    if(setjmp(dispatch)) 
        i = (i+1) % ntasks; 
    while(!quit) 
        task[i](); 
} 

int acc = 0; 

void a(void) { 
    if (acc > 10) quit = 1; 
    printf("A\n"); 
    yield(); 
} 
void b(void) { 
    acc *= 2; 
    printf("B\n"); 
    yield(); 
} 
void c(void) { 
    acc += 1; 
    printf("C\n"); 
    yield(); 
} 

int main() { 
    quit = 0; 
    ntasks = 3; 
    task[0] = a; 
    task[1] = b; 
    task[2] = c; 
    loop(); 
    return 0; 
} 

Der Unterschied zwischen diesem Beispiel und einem Multitasking-Computersystem mit einem Prozessor besteht darin, dass der reale Prozessor das Unterbrechen einer Aufgabe während der Ausführung und die spätere Wiederaufnahme an derselben Stelle unterstützt. Dies ist in einer C-Simulation mit Aufgaben als Einzelfunktionen nicht wirklich möglich. Die Aufgaben könnten jedoch aus einer Folge von C-Funktionen bestehen, die jeweils dem Dispatcher nachgeben (möglicherweise ein Array von Funktionszeigern oder eine verknüpfte Liste).

luser droog
quelle
1
Können Sie bitte eine Beschreibung oder einen Kommentar hinzufügen, um genau zu erklären, was dies zeigen und tun soll? Vielen Dank.
Deanna
Mit einigen Erklärungen bearbeitet. (Ich kann bei Bedarf weitere hinzufügen.)
Luser Droog
Es sieht nicht so aus, als gäbe es eine Möglichkeit, von a zurückzukehren yield(). Daher muss jeder Thread abgeschlossen werden, bevor er Yield aufruft. Es gibt also keine Möglichkeit, mehr als einen Live-Thread gleichzeitig zu haben und nicht zwischen ihnen zu wechseln. Sie können die Dinge also viel einfacher machen, indem Sie einfach die Aufgaben zurückgeben lassen (anstatt Yield aufzurufen) und setjmp/ longjmpüberhaupt nicht verwenden .
Chris Dodd
0

In einem Multithread-Prozess auf einem einzelnen Prozessor kann der Prozessor Ausführungsressourcen zwischen Threads wechseln, was zu einer gleichzeitigen Ausführung führt. Parallelität zeigt an, dass mehr als ein Thread Fortschritte macht, die Threads jedoch nicht gleichzeitig ausgeführt werden. Das Wechseln zwischen Threads erfolgt schnell genug, sodass die Threads möglicherweise gleichzeitig ausgeführt werden.

In demselben Multithread-Prozess in einer Multiprozessor-Umgebung mit gemeinsamem Speicher kann jeder Thread im Prozess gleichzeitig auf einem separaten Prozessor ausgeführt werden, was zu einer parallelen Ausführung führt, was eine echte gleichzeitige Ausführung darstellt. Wenn die Anzahl der Threads in einem Prozess kleiner oder gleich der Anzahl der verfügbaren Prozessoren ist, stellt das Thread-Unterstützungssystem des Betriebssystems sicher, dass jeder Thread auf einem anderen Prozessor ausgeführt wird. Beispielsweise kann in einer Matrixmultiplikation, die mit vier Threads programmiert ist und auf einem System mit zwei Dual-Core-Prozessoren ausgeführt wird, jeder Software-Thread gleichzeitig auf den vier Prozessorkernen ausgeführt werden, um gleichzeitig eine Zeile des Ergebnisses zu berechnen.

Coder123
quelle