Erstellen Sie einen Threadpool in C ++

Erstellen Sie einen Threadpool in C ++
Ein Thread -Pool ist eine Reihe von Threads, bei denen jeder Thread eine Art Aufgabe zur Durchführung hat. Daher führen verschiedene Themen verschiedene Arten von Aufgaben aus. Jeder Thread hat seine Spezialisierung von Aufgaben. Eine Aufgabe ist im Grunde eine Funktion. Ähnliche Funktionen werden von einem bestimmten Thread erfüllt; Eine andere ähnliche Funktionen werden von einem anderen Thread usw. erledigt. Obwohl ein ausführender Thread eine Funktion auf der obersten Ebene ausführt, ist ein Thread per Definition die Instanziierung eines Objekts aus der Thread-Klasse. Unterschiedliche Themen haben unterschiedliche Argumente.

In C ++ muss dieser Thread -Pool verwaltet werden. C ++ hat keine Bibliothek zum Erstellen eines Thread -Pools und ist das Management. Dies liegt wahrscheinlich daran, dass es verschiedene Möglichkeiten gibt, einen Thread -Pool zu erstellen. Ein C ++ - Programmierer muss also einen Thread -Pool basierend auf den Anforderungen erstellen.

Was ist ein Thread? Ein Thread ist ein Objekt, das aus der Thread -Klasse instanziiert ist. In der normalen Instanziierung ist das erste Argument des Thread-Konstruktors der Name einer Funktion auf der obersten Ebene. Der Rest der Argumente an den Thread -Konstruktor sind Argumente für die Funktion. Wenn der Thread instanziiert ist, beginnt die Funktion auszuführen. Die Funktion c ++ main () ist eine Funktion auf der obersten Ebene. Andere Funktionen in diesem globalen Bereich sind Top-Level-Funktionen. Es kommt vor. Betrachten Sie das folgende Programm:

#enthalten
#enthalten
Verwenden von Namespace STD;
void func ()
Cout << "code for first output" << endl;
Cout << "code for second output" << endl;

int main ()

thread thr (func);
TH.verbinden();
/ * Andere Aussagen *//
Rückkehr 0;

Die Ausgabe ist:

Code für die erste Ausgabe
Code für die zweite Ausgabe

Beachten Sie die Einbeziehung der Threadbibliothek mit der Thread -Klasse. func () ist eine obere Funktionsfunktion. Die erste Anweisung in der Funktion main () verwendet sie in der Instanziierung des Threads Thr. Die nächste Aussage in Main () ist eine Join -Erklärung. Es verbindet den Faden THR mit dem Körper des Main () -Funktionsthreads, an der Position, die er codiert ist. Wenn diese Anweisung nicht vorhanden ist, kann die Hauptfunktion ohne Abschluss der Thread -Funktion bis zur Fertigstellung ausführen. Das bedeutet Ärger.

Ein ähnlicher Befehl wie Folgendes sollte verwendet werden, um ein C ++ 20 -Programm von Threads für den G ++ - Compiler auszuführen:

g ++ -std = c ++ 2a tempe.CPP -LPThread -o -Temp

Dieser Artikel erklärt eine Möglichkeit, einen Thread -Pool in C zu erstellen und zu verwalten++.

Artikelinhalt

  • Beispielanforderungen für Threadpool
  • Globale Variablen
  • Die Master -Thread -Funktion
  • Hauptfunktion
  • Abschluss

Beispielanforderungen für Threadpool

Die Anforderungen für diesen veranschaulichen Threadpool sind einfach: Es gibt drei Threads und einen Master -Thread. Die Fäden sind dem Master -Thread untergeordnet. Jeder untergeordnete Thread funktioniert mit einer Warteschlangendatenstruktur. Es gibt also drei Warteschlangen: Qu1, Qu2 und Qu3. Die Warteschlangenbibliothek sowie die Thread -Bibliothek müssen in das Programm aufgenommen werden.

Jede Warteschlange kann mehr als einen Funktionsaufruf haben, jedoch von derselben Funktion der obersten Ebene. Das heißt, jedes Element einer Warteschlange gilt für einen Funktionsaufruf einer bestimmten Funktion auf der oberen Ebene. Es gibt also drei verschiedene Funktionen der obersten Ebene: eine Funktion oberster Ebene pro Thread. Die Funktionsnamen sind FN1, FN2 und FN3.

Die Funktion erfordert für jede Warteschlange nur in ihren Argumenten. Der Einfachheit halber und für dieses Programm Beispiel haben die Funktionsaufrufe kein Argument. Tatsächlich ist der Wert jeder Warteschlange in diesem Beispiel dieselbe Ganzzahl: 1 wie der Wert für alle Qu1 -Elemente; 2 als Wert für alle Qu2 -Elemente; und 3 als Wert für alle Qu3 -Elemente.

Eine Warteschlange ist eine First_in-First_out-Struktur. Der erste Anruf (Nummer) zur Eingabe einer Warteschlange ist also der erste, der abreibt. Wenn ein Anruf (Nummer) verlässt, werden die entsprechende Funktion und sein Thread ausgeführt.

Die Funktion main () ist verantwortlich für die Fütterung jeder der drei Warteschlangen, mit Aufrufen der entsprechenden Funktionen, daher geeignete Threads.

Der Master -Thread ist für die Überprüfung verantwortlich. In diesem Programmbeispiel endet das Programm, wenn keine Warteschlange hat, das Programm endet.

Die obersten Funktionen sind einfach, für dieses pädagogische Beispiel sind sie:

void fn1 ()
Cout << "fn1" << endl;

void fn2 ()
Cout << "fn2" << endl;

void fn3 ()
Cout << "fn3" << endl;

Die entsprechenden Fäden sind Thr1, Thr2 und Thr3. Der Master -Thread hat eine eigene Master -Funktion. Hier hat jede Funktion nur eine Anweisung. Die Ausgabe der Funktion fn1 () lautet "fn1". Die Ausgabe der Funktion fn2 () ist "FN2". Die Ausgabe der Funktion fn3 () ist "fn3".

Am Ende dieses Artikels kann der Leser alle Codesegmente in diesem Artikel zusammenstellen, um ein Thread -Pool -Programm zu bilden.

Globale Variablen

Die Spitze des Programms mit den globalen Variablen ist:

#enthalten
#enthalten
#enthalten
Verwenden von Namespace STD;
Warteschlange qu1;
Warteschlange qu2;
Warteschlange qu3;
Thread Thr1;
Thread Thr2;
Thread Thr3;

Die Warteschlangen- und Fadenvariablen sind globale Variablen. Sie wurden ohne Initialisierung oder Erklärung deklariert. Danach sollte im Programm die drei untergeordneten Funktionen der obersten Ebene sein, wie oben gezeigt.

Die iOstream -Bibliothek ist für das Cout -Objekt enthalten. Die Threadbibliothek ist für die Threads enthalten. Die Namen der Threads sind Thr1, Thr2 und Thr3. Die Warteschlangenbibliothek ist für die Warteschlangen enthalten. Die Namen der Warteschlangen sind Qu1, Qu2 und Qu3. Qu1 entspricht Thr1; Qu2 entspricht Thr2 und Qu3 entspricht Thr3. Eine Warteschlange ist wie ein Vektor, aber es ist für FIFO (First_in-first_out).

Die Master -Thread -Funktion

Nach den drei untergeordneten Funktionen der oberen Ebene sind die Masterfunktion im Programm. Es ist:

void masterfn ()
arbeiten:
if (qu1.size ()> 0) thr1 = thread (fn1);
if (qu2.size ()> 0) thr2 = thread (fn2);
if (qu3.size ()> 0) thr3 = thread (fn3);
if (qu1.size ()> 0)
Qu1.Pop();
Thr1.verbinden();

if (qu2.size ()> 0)
qu2.Pop();
Thr2.verbinden();

if (qu3.size ()> 0)
Qu3.Pop();
Thr3.verbinden();

if (qu1.size () == 0 && qu1.size () == 0 && qu1.size () == 0)
zurückkehren;
geh zur Arbeit;

Die Goto-Loop verkörpert den gesamten Code der Funktion. Wenn alle Warteschlangen leer sind, kehrt die Funktion mit der Anweisung „Rückgabe“ ungültig zurück.

Das erste Codesegment in der Goto-Loop enthält drei Aussagen: eine für jede Warteschlange und den entsprechenden Thread. Wenn eine Warteschlange nicht leer ist, wird ihr Faden (und die entsprechende Funktion untergeordneter oberster Ebene) ausgeführt.

Das nächste Code-Segment besteht aus drei If-Constructe, die jeweils einem untergeordneten Thread entsprechen. Jedes If-Construct hat zwei Aussagen. Die erste Anweisung beseitigt die Nummer (für den Anruf), der möglicherweise im ersten Codesegment stattgefunden hat. Die nächste ist eine Join -Anweisung, die sicherstellt.

Die letzte Aussage in der Goto-Loop beendet die Funktion und geht aus der Schleife, wenn alle Warteschlangen leer sind.

Hauptfunktion

Nach der Master -Thread -Funktion im Programm sollte die main () -Funktion sein, deren Inhalt lautet:

Qu1.Push (1);
Qu1.Push (1);
Qu1.Push (1);
qu2.Push (2);
qu2.Push (2);
Qu3.Push (3);
Thread Masterthr (Masterfn);
Cout << "Program has started:" << endl;
Meisterschaft.verbinden();
Cout << "Program has ended." << endl;

Die Funktion main () ist dafür verantwortlich, Nummern zu setzen, die Aufrufe in die Warteschlangen darstellen. Qu1 hat drei Werte von 1; Qu2 hat zwei Werte von 2 und Qu3 einen Wert von 3. Die main () -Funktion startet den Master -Thread und verbindet ihn mit ihrem Körper. Eine Ausgabe des Computers des Autors ist:

Das Programm hat begonnen:
fn2
fn3
fn1
fn1
fn2
fn1
Das Programm ist beendet.

Der Ausgang zeigt die unregelmäßigen gleichzeitigen Operationen von Threads. Bevor die main () -Funktion mit seinem Master -Thread angeschlossen ist, wird "Programm gestartet:" angezeigt: ". Der Master -Thread ruft Thr1 für fn1 (), Thr2 für FN2 () und Thr3 für fn3 () in dieser Reihenfolge auf. Die entsprechende Ausgabe beginnt jedoch mit "FN2", "fn3" und dann "fn1". An dieser ersten Reihenfolge ist nichts auszusetzen. So funktioniert die Parallelität unregelmäßig. Der Rest der Ausgangszeichenfolgen erscheinen, als ihre Funktionen genannt wurden.

Nachdem sich der Hauptfunktionskörper dem Master -Thread angeschlossen hatte, wartete er darauf, dass der Master -Thread fertiggestellt wurde. Damit der Master -Thread abgeschlossen ist, müssen alle Warteschlangen leer sein. Jeder Warteschlangenwert entspricht der Ausführung seines entsprechenden Threads. Damit jede Warteschlange leer wird, muss sein Thread für diese Häufigkeit ausgeführt werden. Es gibt Elemente in der Warteschlange.

Wenn der Master -Thread und seine Threads ausgeführt und beendet wurden, wird die Hauptfunktion weiterhin ausgeführt. Und es zeigt: „Das Programm ist beendet.”.

Abschluss

Ein Threadpool ist ein Satz von Threads. Jeder Thread ist für die Ausführung seiner eigenen Aufgaben verantwortlich. Aufgaben sind Funktionen. Theoretisch kommen immer die Aufgaben. Sie enden nicht wirklich, wie im obigen Beispiel dargestellt. In einigen praktischen Beispielen werden Daten zwischen Threads geteilt. Um Daten zu teilen, benötigt der Programmierer Kenntnisse über Conditional_Variable, Asynchronous -Funktion, Versprechen und Zukunft. Das ist eine Diskussion für einige andere Zeit.