Ich versuche, Multithreading in c ++ zu verstehen, aber ich stecke in diesem Problem fest: Wenn ich Threads in einer for-Schleife starte, drucken sie falsche Werte. Dies ist der Code:
#include <iostream>
#include <list>
#include <thread>
void print_id(int id){
printf("Hello from thread %d\n", id);
}
int main() {
int n=5;
std::list<std::thread> threads={};
for(int i=0; i<n; i++ ){
threads.emplace_back(std::thread([&](){ print_id(i); }));
}
for(auto& t: threads){
t.join();
}
return 0;
}
Ich hatte erwartet, dass die Werte 0,1,2,3,4 gedruckt werden, aber ich habe oft zweimal den gleichen Wert erhalten. Dies ist die Ausgabe:
Hello from thread 2
Hello from thread 3
Hello from thread 3
Hello from thread 4
Hello from thread 5
Was fehlt mir?
c++
multithreading
Ermando
quelle
quelle
i
den Wert an Lambda[i]
.emplace_back
seltsam ist:emplace_back
Nimmt eine Liste von Argumenten und gibt diese an einen Konstruktor für weiterstd::thread
. Sie haben eine (rvalue) -Instanz von übergebenstd::thread
, erstellen daher einen Thread und verschieben diesen Thread in den Vektor. Diese Operation wird besser durch die allgemeinere Methode ausgedrücktpush_back
. Es wäre sinnvoller, entweder zu schreibenthreads.emplace_back([i](){ print_id(i); });
(Konstrukt an Ort und Stelle) oderthreads.push_back(std::thread([i](){ print_id(i); }));
(Konstrukt + Verschieben), die etwas idiomatischer sind.Antworten:
Die
[&]
Syntax bewirkti
, dass sie als Referenz erfasst wird . Daher wird es ziemlich ofti
weiter fortgeschritten sein, wenn der Thread ausgeführt wird, als Sie vielleicht erwarten. Im Ernst, das Verhalten Ihres Codes ist undefiniert, wenni
der Gültigkeitsbereich überschritten wird, bevor ein Thread ausgeführt wird.Erfassung
i
nach Wert - dhstd::thread([i](){ print_id(i); })
ist die Lösung.quelle
std::thread([=](){ print_id(i); })
i
bei dem der Haupt-Thread geschrieben und die anderen Threads gelesen werden.Zwei Probleme:
Sie haben keine Kontrolle darüber, wann der Thread ausgeführt wird. Dies bedeutet, dass der Wert der Variablen
i
im Lambda möglicherweise nicht Ihren Erwartungen entspricht.Die Variable
i
ist lokal für die Schleife und nur für die Schleife. Wenn die Schleife beendet wird, bevor ein oder mehrere Threads ausgeführt werden, haben diese Threads einen ungültigen Verweis auf eine Variable, deren Lebensdauer abgelaufen ist.Sie können diese beiden Probleme sehr einfach lösen, indem Sie die Variable
i
nach Wert anstatt nach Referenz erfassen . Das bedeutet, dass jeder Thread eine Kopie des Werts hat und diese Kopie für jeden Thread eindeutig erstellt wird.quelle
Eine andere Sache:
Warten Sie nicht, bis Sie immer eine geordnete Sequenz haben: 0, 1, 2, 3, ... denn der Multithreading-Ausführungsmodus hat eine Besonderheit: Indeterminismus .
Indeterminismus bedeutet, dass die Ausführung desselben Programms unter denselben Bedingungen zu einem anderen Ergebnis führt.
Dies liegt an der Tatsache, dass das Betriebssystem Threads von Ausführung zu Ausführung unterschiedlich plant, abhängig von mehreren Parametern: CPU-Auslastung, Priorität anderer Prozesse, mögliche Systemunterbrechungen, ...
Ihr Beispiel enthält nur 5 Threads. Versuchen Sie also einfach, die Anzahl der Threads zu erhöhen. Wenn Sie beispielsweise die Verarbeitungsfunktion in den Ruhezustand versetzen, werden Sie feststellen, dass das Ergebnis von Ausführung zu Ausführung unterschiedlich sein kann.
quelle