C ++ Join Thread

C ++ Join Thread
Themen sind wie Unterprogramme zu einem Programm. Und so würden sie unabhängig laufen. Das Verbinden bedeutet, dass ein Thread ausgeführt wird, bis er einen bestimmten Punkt erreicht und dann auf ein anderes Thread wartet, um seine Ausführung (bis zu seinem Ende) zu beenden. bevor es seine eigene Ausführung fortsetzt. An dem Punkt, an dem der erste Thread anhält, gibt es eine Join -Anweisung. Ein Thread kann einen anderen Thread aufrufen. Es ist der Thread, der anruft, der sich verbindet. Der angerufene Thread verbindet nicht.

Das Verbinden existiert, weil Threads miteinander kommunizieren müssen. Nachdem die Änderung stattgefunden hat, kann der aufgerufene Thread den Wert einer globalen Variablen ändern, auf die der aufrufende Thread zugreifen muss. Dies ist eine Form der Synchronisation.

Dieser Artikel erklärt zwei Möglichkeiten, Threads beizutreten. Es beginnt mit einer Illustration dessen, was ein Thread ist.

Artikelinhalt

  • Gewinde
  • Einen Thread verbinden
  • Zukunft :: Get ()
  • Abschluss

Gewinde

Betrachten Sie das folgende Programm:

#enthalten
Verwenden von Namespace STD;
void fn2 ()
Cout << "function 2" << '\n';

void fn1 ()
Cout << "function 1" << '\n';

int main ()

/ * einige Aussagen */
Rückkehr 0;

fn1 (), fn2 () und main () sind Funktionen auf höchster Ebene, obwohl main () eine Schlüsselfunktion ist. Aus diesen drei obersten Funktionen können drei Themen erhalten werden. Das folgende sehr einfache kurze Programm ist ein natürlicher Faden:

#enthalten
Verwenden von Namespace STD;
int main ()

/ * einige Aussagen */
Rückkehr 0;

Die main () -Funktion verhält sich wie ein Thread. Es kann als Hauptfaden angesehen werden. Es muss in keiner Instanziierung aus der Thread -Klasse eingekapselt werden. Das vorherige Programm mit Funktionen auf höchster Ebene, die die Funktion main () enthält, ist also immer noch ein Thread. Das folgende Programm zeigt, wie die beiden Funktionen FN1 () und FN2 () in Threads konvertiert werden können, jedoch ohne eine Join -Anweisung:

#enthalten
#enthalten
#enthalten
Verwenden von Namespace STD;
String Globl1 = String ("SO,");
String Globl2 = String ("sei es!");
void fn2 (String st2)
String Globl = Globl1 + ST2;
Cout << globl << endl;

void fn1 (String st1)
Globl1 = "Ja. " + st1;
Thread Thr2 (fn2, globl2);

int main ()

Thread Thr1 (fn1, globl1);
/ * einige Aussagen */
Rückkehr 0;

Das Programm beginnt mit der Aufnahme der iStream -Bibliothek für das Cout -Objekt. Dann ist die Threadbibliothek enthalten. Einschließlich der Thread -Bibliothek ist ein Muss; Damit der Programmierer einfach ein Thread-Objekt aus der Thread-Klasse unter Verwendung einer Funktion der obersten Ebene mit Ausnahme der Funktion main () aus der Thread-Klasse instanziiert.

Danach ist die String -Bibliothek enthalten. Diese Bibliothek vereinfacht die Verwendung von String -Literalen. Die erste Aussage im Programm besteht darin.

Die nächsten beiden Aussagen erklären zwei globale String -Objekte mit ihren Literalen. Die String -Objekte werden Globl1 und Globl2 bezeichnet. Es gibt die Funktion fn1 () und die Funktion fn2 (). Der Name der FN2 () -Funktion wird als eines der Argumente zum Instanziieren des Threads Thr2 aus der Thread -Klasse verwendet. Wenn eine Funktion auf diese Weise instanziiert wird, wird die Funktion aufgerufen; Und es wird ausgeführt. Wenn die Fn2 () -Funktion aufgerufen wird, verkettet sie die String -Literale von Globl1 und Globl2, um „so, sei es!”. Globl2 ist das Argument von FN2 ().

Der Name der Funktion fn1 () wird als Argument zur Instanziierung des Threads Thr1 aus der Thread -Klasse verwendet. Während dieser Instanziation wird FN1 () genannt. Wenn es aufgerufen wird, geht es der Saite voraus: „Also, sei es!”Mit" Ja. ", zu haben" ja. So sei es!", das ist die Ausgabe für das gesamte Programm von Threads.

Die Main () -Funktion, die der Main () -Thread ist, instanziiert den Thread Thr1 aus der Thread -Klasse mit den Argumenten Fn1 und Globl1. Während dieser Instanziation wird FN1 () genannt. Die Funktion fn1 () ist der effektive Faden für das Objekt, Thr1. Wenn eine Funktion aufgerufen wird, sollte sie von Anfang an bis zu ihrem Ende ausgeführt werden.

Thr1, der effektiv fn1 () ist, instanziiert den Thread, Thr2, aus der Thread -Klasse mit den Argumenten FN2 und Globl2. Während dieser Instanziation wird FN2 () genannt. Die Funktion fn2 () ist der effektive Faden für das Objekt, Thr2. Wenn eine Funktion aufgerufen wird, sollte sie von Anfang an bis zu ihrem Ende ausgeführt werden.

Wenn der Leser, der G ++ - Compiler verwendet, kann er dieses Programm von Threads für C ++ 20 -Kompilierung mit dem folgenden Befehl testen:

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

Der Autor tat dies; leitete das Programm und hatte die Ausgabe:

Beenden Sie ohne aktive Ausnahme bezeichnet
Abgebildet (Kerngeladen)

Es ist möglich, eine fehlerhafte Ausgabe wie diese zu haben, mit der richtigen Ausgabe von "Ja". So sei es!", innerhalb. Alles, was immer noch inakzeptabel ist.

Das Problem mit dieser fehlerhaften Ausgabe ist, dass Threads nicht verbunden wurden. Und so wurden die Threads unabhängig voneinander betrieben, was zu Verwirrung führte. Die Lösung besteht darin, THR1 mit dem Hauptfaden zu verbinden, und da Thr1 Thr2 aufruft, so wie der Hauptfaden Thr1 aufruft, muss Thr2 mit Thr1 verbunden werden. Dies ist im nächsten Abschnitt dargestellt.

Einen Thread verbinden

Die Syntax, um einen Thread mit dem aufrufenden Thread zu verbinden, lautet:

Threadobj.verbinden();

wobei Join () eine Mitgliedsfunktion eines Thread -Objekts ist. Dieser Ausdruck muss sich im Körper des aufrufenden Threads befinden. Dieser Ausdruck muss sich im Körper der Aufruffunktion befinden, was ein effektiver Faden ist.

Das folgende Programm ist das obige Programm, das wiederholt wurde, aber mit dem Körper des Hauptfadens, das Thr1 verbindet und der Körper von Thr1 Thr2 verbindet:

#enthalten
#enthalten
#enthalten
Verwenden von Namespace STD;
String Globl1 = String ("SO,");
String Globl2 = String ("sei es!");
void fn2 (String st2)
String Globl = Globl1 + ST2;
Cout << globl << endl;

void fn1 (String st1)
Globl1 = "Ja. " + st1;
Thread Thr2 (fn2, globl2);
Thr2.verbinden();

int main ()

Thread Thr1 (fn1, globl1);
Thr1.verbinden();
/ * einige Aussagen */
Rückkehr 0;

Beachten Sie die Wartepositionen, in denen die Join -Anweisungen in das Programm eingefügt wurden. Die Ausgabe ist:

"Ja. So sei es!”

Ohne die Zitate, wie erwartet, sauber und klar, eindeutig “. Thr2 braucht keine Join -Aussage in seinem Körper; Es ruft keinen Thread auf.

Also verbindet der Körper des Ruffadens den angerufenen Thread.

Zukunft :: Get ()

Die C ++-Standardbibliothek verfügt über eine Unter-Bibliothek namens Future. Diese Unter-Bibliothek hat eine Klasse namens Future. Die Bibliothek hat auch eine Funktion namens Async (). Die Klasse, die Zukunft, hat eine Mitgliedsfunktion namens Get (). Zusätzlich zu ihrer Hauptaufgabe hat diese Funktion den Einfluss, zwei Funktionen zu verbinden, die gleichzeitig oder parallel laufen. Die Funktionen müssen keine Fäden sein.

Die async () -Funktion

Beachten Sie, dass die über alle Threads zurückgegebenen Leere. Ein Thread ist eine Funktion, die unter Kontrolle steht. Einige Funktionen kehren nicht ungültig zurück, sondern etwas zurück. Einige Threads geben also etwas zurück.

Die async () -Funktion kann eine oberste Funktion als Argument aufnehmen und die Funktion gleichzeitig oder parallel zur Aufruffunktion ausführen. In diesem Fall gibt es keine Threads, nur eine Aufruffunktion und eine aufgerufene Funktion, die als Argument für die async () -Funktion bezeichnet wird. Eine einfache Syntax für die asynchronisierende Funktion ist:

zukünftige futobj = async (fn, fnargs)

Die asynchronisierte Funktion gibt ein zukünftiges Objekt zurück. Das erste Argument hier für die asynchronische Funktion ist der Name der obersten Funktionsfunktion. Danach kann es mehr als ein Argument geben. Der Rest der Argumente sind Argumente zur obersten Funktion der obersten Ebene.

Wenn die Funktion der obersten Ebene einen Wert zurückgibt, ist dieser Wert ein Mitglied des zukünftigen Objekts. Und dies ist eine Möglichkeit, einen Thread nachzuahmen, der einen Wert zurückgibt.

Zukunft :: Get ()

Die asynchronisierte Funktion gibt ein zukünftiges Objekt zurück. Dieses zukünftige Objekt hat den Rückgabewert der Funktion, das ein Argument für die asynchronisierte Funktion ist. Um diesen Wert zu erhalten, muss die Funktion get () Mitglied des zukünftigen Objekts verwendet werden. Das Szenario ist:

zukünftige futobj = asynchron (fn, fnargs);
Geben Sie Futobj ein.erhalten();

Wenn die Funktion get () aufgerufen wird, wartet der Körper der Aufruffunktion (Blöcke), bis die asynchronisierte Funktion ihren Wert zurückgegeben hat. Danach wird der Rest der Aussagen unter der Erklärung get () weiter ausgeführt.

Das folgende Programm ist das oben genannte, bei dem offiziell kein Thread erstellt wurde und anstelle der Join -Erklärung die Erklärung get () verwendet wurde. Die async () -Funktion wurde verwendet, um einen Thread zu simulieren. Die beiden Funktionen der obersten Ebene wurden auf einen reduziert. Das Programm ist:

#enthalten
#enthalten
#enthalten
Verwenden von Namespace STD;
String Globl1 = String ("SO,");
String Globl2 = String ("sei es!");
String fn (String ST1, String ST2)
String concat = ST1 + ST2;
Rückgabeconat;

int main ()

zukünftige fut = asynchronisiert (fn, globl1, globl2);
String ret = fut.erhalten(); // main () wartet hier
String result = "Ja. " + ret;
Cout << result << endl;
Rückkehr 0;

Beachten Sie, dass die zukünftige Bibliothek anstelle der Thread -Bibliothek enthalten ist. Die Ausgabe ist:

Ja. So sei es!

Abschluss

Wenn es um eine Beitrittserklärung geht, sind zwei Funktionen auf der Top-Ebene beteiligt. Einer ist die Aufruffunktion, und der andere ist die aufgerufene Funktion. Im Körper der Aufruffunktion befindet sich die Join -Anweisung. Diese beiden Funktionen können jeweils in einem Thread eingekapselt werden. Die Funktion Join () Mitglied des aufgerufenen Threads befindet sich im Körper des aufrufenden Threads. Wenn die Funktion Join () aufgerufen wird, wartet der aufrufende Thread an diesem Punkt (Blöcke), bis der aufgerufene Thread abgeschlossen ist. bevor es weiter funktioniert.

Die Verwendung von Threads kann durch die Verwendung der async () -Funktion in der zukünftigen Bibliothek vermieden werden. Diese Funktion nimmt eine Funktion auf der obersten Ebene als Argument und gibt ein zukünftiges Objekt zurück, das den zurückgegebenen Wert der Argumentfunktion an die async () -Funktion enthält. Um den Rückgabewert der Funktion als Argument zu erhalten. Wenn die Get () -Mitglied -Funktion aufgerufen wird, wartet die Aufruffunktion an diesem Punkt (Blöcke), bis die aufgerufene Funktion abgeschlossen ist. bevor es weiter funktioniert.