Relevante Fragen :
Über C ++ 11:
- C ++ 11: std :: thread gepoolt?
- Wird Async (launch :: async) in C ++ 11 Thread-Pools überflüssig machen, um teure Thread-Erstellung zu vermeiden?
Über Boost:
Wie erhalte ich einen Pool von Threads, an die Aufgaben gesendet werden können, ohne sie immer wieder zu erstellen und zu löschen? Dies bedeutet, dass persistente Threads ohne Verknüpfung neu synchronisiert werden müssen.
Ich habe Code, der so aussieht:
namespace {
std::vector<std::thread> workers;
int total = 4;
int arr[4] = {0};
void each_thread_does(int i) {
arr[i] += 2;
}
}
int main(int argc, char *argv[]) {
for (int i = 0; i < 8; ++i) { // for 8 iterations,
for (int j = 0; j < 4; ++j) {
workers.push_back(std::thread(each_thread_does, j));
}
for (std::thread &t: workers) {
if (t.joinable()) {
t.join();
}
}
arr[4] = std::min_element(arr, arr+4);
}
return 0;
}
Anstatt Threads bei jeder Iteration zu erstellen und zu verknüpfen, würde ich es vorziehen, Aufgaben bei jeder Iteration an meine Worker-Threads zu senden und sie nur einmal zu erstellen.
c++
multithreading
c++11
threadpool
stdthread
Yktula
quelle
quelle
Antworten:
Sie können die C ++ - Thread-Pool-Bibliothek unter https://github.com/vit-vit/ctpl verwenden .
Dann kann der von Ihnen geschriebene Code durch den folgenden ersetzt werden
Sie erhalten die gewünschte Anzahl von Threads und werden diese bei den Iterationen nicht immer wieder erstellen und löschen.
quelle
results[j] = p.push([&arr, j](int){ arr[j] +=2; });
Dies wird von meiner Antwort auf einen anderen sehr ähnlichen Beitrag kopiert, hoffe es kann helfen:
1) Beginnen Sie mit der maximalen Anzahl von Threads, die ein System unterstützen kann:
2) Für eine effiziente Threadpool-Implementierung ist es besser, nach dem Erstellen von Threads gemäß Num_Threads keine neuen zu erstellen oder alte zu zerstören (durch Verbinden). Dies führt zu Leistungseinbußen und kann sogar dazu führen, dass Ihre Anwendung langsamer als die serielle Version wird.
Jeder C ++ 11-Thread sollte in seiner Funktion mit einer Endlosschleife ausgeführt werden und ständig darauf warten, dass neue Aufgaben erfasst und ausgeführt werden.
So fügen Sie eine solche Funktion dem Thread-Pool hinzu:
3) Die Infinite_loop_function
Dies ist eine "while (true)" - Schleife, die auf die Task-Warteschlange wartet
4) Erstellen Sie eine Funktion, um Ihrer Warteschlange einen Job hinzuzufügen
5) Binden Sie eine beliebige Funktion an Ihre Warteschlange
Sobald Sie diese Zutaten integriert haben, haben Sie Ihren eigenen dynamischen Threading-Pool. Diese Threads werden immer ausgeführt und warten auf die Ausführung des Jobs.
Ich entschuldige mich, wenn es einige Syntaxfehler gibt, ich habe diesen Code eingegeben und ich habe ein schlechtes Gedächtnis. Es tut mir leid, dass ich Ihnen nicht den vollständigen Thread-Pool-Code zur Verfügung stellen kann, der meine Jobintegrität verletzen würde.
Bearbeiten: Um den Pool zu beenden, rufen Sie die Methode shutdown () auf:
quelle
std::vector
erfordert nicht, dass seine Elemente kopierbar sind. Sie können Vektoren mit Nur-Verschieben-Typen verwenden (unique_ptr
,thread
,future
, etc.).condition.wait
auch nach einer Variablen suchenstop_
und prüfenif (stop_ == true) { break;}
?Ein Pool von Threads bedeutet, dass alle Ihre Threads ständig ausgeführt werden - mit anderen Worten, die Thread-Funktion wird nie zurückgegeben. Um den Threads eine sinnvolle Aufgabe zu geben, müssen Sie ein System für die Kommunikation zwischen Threads entwerfen, um dem Thread mitzuteilen, dass etwas zu tun ist, und um die tatsächlichen Arbeitsdaten zu kommunizieren.
In der Regel handelt es sich dabei um eine gleichzeitige Datenstruktur, und jeder Thread befindet sich vermutlich in einer Bedingungsvariablen, die benachrichtigt wird, wenn noch etwas zu tun ist. Nach Erhalt der Benachrichtigung werden einer oder mehrere der Threads aktiviert, stellen eine Aufgabe aus der gleichzeitigen Datenstruktur wieder her, verarbeiten sie und speichern das Ergebnis auf analoge Weise.
Der Thread würde dann prüfen, ob noch mehr Arbeit zu erledigen ist, und wenn nicht, wieder einschlafen.
Das Ergebnis ist, dass Sie dies alles selbst entwerfen müssen, da es keinen natürlichen Begriff von "Arbeit" gibt, der universell anwendbar ist. Es ist ziemlich viel Arbeit und es gibt einige subtile Probleme, die Sie richtig stellen müssen. (Sie können in Go programmieren, wenn Sie ein System mögen, das sich hinter den Kulissen um die Thread-Verwaltung kümmert.)
quelle
Ein Threadpool ist im Kern eine Reihe von Threads, die alle an eine Funktion gebunden sind, die als Ereignisschleife fungiert. Diese Threads warten endlos auf die Ausführung einer Aufgabe oder ihre eigene Beendigung.
Der Threadpool-Job soll eine Schnittstelle zum Übermitteln von Jobs, zum Definieren (und möglicherweise Ändern) der Richtlinie zum Ausführen dieser Jobs (Planungsregeln, Thread-Instanziierung, Größe des Pools) und zum Überwachen des Status der Threads und der zugehörigen Ressourcen bereitstellen.
Für einen vielseitigen Pool muss zunächst definiert werden, was eine Aufgabe ist, wie sie gestartet, unterbrochen, was das Ergebnis ist (siehe den Begriff des Versprechens und der Zukunft für diese Frage) und welche Art von Ereignissen die Threads beantworten müssen zu, wie sie damit umgehen, wie diese Ereignisse von denen zu unterscheiden sind, die von den Aufgaben behandelt werden. Wie Sie sehen, kann dies ziemlich kompliziert werden und die Funktionsweise der Threads einschränken, da die Lösung immer komplexer wird.
Das aktuelle Tool für die Behandlung von Ereignissen ist ziemlich barebones (*): Grundelemente wie Mutexe, Bedingungsvariablen und einige Abstraktionen (Sperren, Barrieren). In einigen Fällen können sich diese Abstrationen jedoch als ungeeignet herausstellen (siehe diese verwandte Frage ), und man muss wieder die Grundelemente verwenden.
Andere Probleme müssen ebenfalls gelöst werden:
Wie würden sich diese in Ihrer Umgebung auswirken?
Diese Antwort auf eine ähnliche Frage verweist auf eine bestehende Implementierung, die für Boost und STL gedacht ist.
Ich habe eine sehr grobe Implementierung eines Threadpools für eine andere Frage angeboten, die nicht viele der oben beschriebenen Probleme anspricht. Vielleicht möchten Sie darauf aufbauen. Vielleicht möchten Sie auch einen Blick auf vorhandene Frameworks in anderen Sprachen werfen, um Inspiration zu finden.
(*) Ich sehe das nicht als Problem, ganz im Gegenteil. Ich denke, es ist der Geist von C ++, der von C geerbt wurde.
quelle
quelle
So etwas könnte helfen (aus einer funktionierenden App).
Sie können es so verwenden:
Beachten Sie, dass die Neuerfindung eines effizienten asynchronen Warteschlangenmechanismus nicht trivial ist.
Boost :: asio :: io_service ist eine sehr effiziente Implementierung oder eine Sammlung plattformspezifischer Wrapper (z. B. umschließt E / A-Abschlussports unter Windows).
quelle
std::thread
ausreichend?std
fürboost::thread_group
.boost::thread_group
ist eine Sammlung vonboost::thread
Instanzen. Aber natürlich ist es sehr einfach, durchboost::thread_group
einvector
vonstd::thread
s zu ersetzen .Bearbeiten: Dies erfordert jetzt C ++ 17 und Konzepte. (Ab dem 12.9.16 ist nur g ++ 6.0+ ausreichend.)
Der Abzug von Vorlagen ist jedoch viel genauer, sodass sich die Mühe lohnt, einen neueren Compiler zu erwerben. Ich habe noch keine Funktion gefunden, die explizite Vorlagenargumente erfordert.
Es nimmt jetzt auch jedes geeignete aufrufbare Objekt ( und ist statisch immer noch typsicher !!! ).
Es enthält jetzt auch einen optionalen Green Threading-Prioritäts-Thread-Pool, der dieselbe API verwendet. Diese Klasse ist jedoch nur POSIX. Es verwendet die
ucontext_t
API für das Wechseln von Userspace-Aufgaben.Ich habe dafür eine einfache Bibliothek erstellt. Ein Anwendungsbeispiel ist unten angegeben. (Ich beantworte dies, weil es eines der Dinge war, die ich gefunden habe, bevor ich beschlossen habe, es selbst zu schreiben.)
Sie können
async
jede Funktion mit einem beliebigen (oder ungültigen) Rückgabewert und beliebigen (oder keinen) Argumenten übergeben, und es wird ein entsprechender zurückgegebenstd::future
. Um das Ergebnis zu erhalten (oder einfach zu warten, bis eine Aufgabe abgeschlossen ist), rufen Sieget()
die Zukunft an.Hier ist der Github: https://github.com/Tyler-Hardin/thread_pool .
quelle
Dies ist eine weitere Thread-Pool-Implementierung, die sehr einfach, leicht zu verstehen und zu verwenden ist, nur die C ++ 11-Standardbibliothek verwendet und für Ihre Zwecke angesehen oder geändert werden kann. Sie sollte ein guter Einstieg sein, wenn Sie mit der Verwendung von Thread beginnen möchten Pools:
https://github.com/progschj/ThreadPool
quelle
Sie können thread_pool aus der Boost-Bibliothek verwenden:
Sie können auch Threadpool aus der Open Source-Community verwenden:
quelle
Ein Threadpool ohne Abhängigkeiten außerhalb von STL ist durchaus möglich. Ich habe kürzlich eine kleine Threadpool-Bibliothek nur für Header geschrieben , um genau das gleiche Problem zu beheben. Es unterstützt die dynamische Größenänderung des Pools (Ändern der Anzahl der Mitarbeiter zur Laufzeit), Warten, Stoppen, Anhalten, Fortsetzen usw. Ich hoffe, Sie finden es nützlich.
quelle