C++-Multithreading-Bibliothek<thread>
C++11 führte Multithreading-Unterstützung ein, durch<thread>die Bibliothek, können Entwickler problemlos Parallelverarbeitung in Programmen implementieren.
Dieser Artikel führt ein in<thread>die grundlegenden Konzepte, Definitionen, Syntax der Bibliothek und wie man sie zum Erstellen und Verwalten von Threads verwendet.
Ein Thread ist die kleinste Einheit der Programmausführung und die kleinste Einheit, die das Betriebssystem zur Berechnung einplanen kann.
In Multithread-Programmen können mehrere Threads parallel ausgeführt werden, wodurch die Ausführungseffizienz des Programms verbessert wird.
C++ <thread>Bibliotheksübersicht
<thread>Die Bibliothek ist Teil der C++-Standardbibliothek und bietet die grundlegende Funktionalität zum Erstellen und Verwalten von Threads. Sie umfasst die folgenden Schlüsselkomponenten:
std::thread: Stellt einen Thread dar; er kann Threads erstellen, starten, auf sie warten und sie zerstören.std::this_thread: Bietet einige statische Memberfunktionen für die Arbeit mit dem aktuellen Thread.std::thread::id: Der eindeutige Bezeichner des Threads.
Threads erstellen
Um einen Thread zu erstellen, müssen Siestd::threaddie Klasse instanziieren und ein aufrufbares Objekt (Funktion, Lambda-Ausdruck oder Memberfunktion eines Objekts) als Argument übergeben.
Beispiel
#include <thread>
void print_id(int id) {
std::cout << "ID: " << id << ", Thread ID: " << std::this_thread::get_id() << std::endl;
}
int main() {
std::thread t1(print_id, 1);
std::thread t2(print_id, 2);
}
Threads starten
Erstellestd::threadNach dem Objekt beginnt der Thread sofort mit der Ausführung; Sie könnenjoin()Methode aufrufen, um zu warten, bis der Thread abgeschlossen ist.
t1.join(); t2.join();
Warten auf die Beendigung des Threads
join()Methode blockiert den aktuellen Thread, bis der aufgerufene Thread die Ausführung abgeschlossen hat.
Threads zerstören
Wenn der Thread die Ausführung beendet hat, können Siedetach()Methode verwenden, um den Thread loszulösen, oder lassen Siestd::threaddas Objekt den Gültigkeitsbereich verlassen und automatisch zerstört werden.
t1.detach(); // 线程将继续运行,但无法再被 join oder detach
Beispiel: Verwendung von<thread>Parallele Berechnung erstellen
Nachfolgend ein Beispiel unter Verwendung von<thread>Beispiel für paralleles Rechnen, das mit der Bibliothek implementiert wurde und die Summe zweier Zahlen berechnet.
Beispiel
#include <thread>
int sum = 0;
void add(int a, int b) {
sum += a + b;
}
int main() {
int a = 5;
int b = 10;
std::thread t1(add, a, b);
std::thread t2(add, a, b);
t1.join();
t2.join();
std::cout << "Summe: " << sum << std::endl; // Ergebnis ausgeben: Summe: 30
}
Das Ausgabeergebnis ist:
Sum: 30
Im folgenden Beispiel erstellen wir zwei Threads, von denen jeder eine einfache Funktion ausführt, die eine Nachricht ausgibt und eine Weile schläft:
Beispiel
#include <thread>
#include <chrono>
// Einfache Funktion, die in einem Thread ausgeführt wird
void print_message(const std::string& message, int delay) {
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
std::cout << message << std::endl;
}
int main() {
// Zwei Threads erstellen und die Funktion print_message ausführen
std::thread t1(print_message, "Hallo von Thread 1", 1000);
std::thread t2(print_message, "Hallo von Thread 2", 500);
// Warten, bis Thread t1 beendet ist
if (t1.joinable()) {
t1.join();
}
// Warten, bis Thread t2 beendet ist
if (t2.joinable()) {
t2.join();
}
std::cout << "Hauptthread beendet." << std::endl;
return 0;
}
Das Ausgabeergebnis ist:
Hello from thread 2 Hello from thread 1 Main thread finished.
Hinweise
- Thread-Sicherheit: In einer Multithread-Umgebung erfordern gemeinsam genutzte Ressourcen synchronisierten Zugriff, um Datenrennen zu vermeiden.
- Thread-Lebenszyklus: Stellen Sie sicher, dass das Thread-Objekt nach Abschluss der Thread-Ausführung korrekt behandelt wird, um Ressourcenlecks zu vermeiden.
Klassen und Funktionen
<thread>Die Bibliothek enthält eine Reihe von Klassen und Funktionen zum Erstellen, Verwalten und Synchronisieren von Threads.
Im Folgenden geht es um C++<thread>Ausführliche Einführung in die Bibliothek:
Hauptkomponenten
- std::thread
- std::mutex
- std::lock_guard
- std::unique_lock
- std::condition_variable
- std::future und std::promise
- std::async
std::thread
Die Klasse std::thread wird zum Erstellen und Verwalten von Threads verwendet.
Beispiel
#include <thread>
void print_hello() {
std::cout << "Hallo vom Thread!" << std::endl;
}
int main() {
std::thread t(print_hello);
t.join(); // Warten, bis Thread t fertig ist
return 0;
}
Wichtige Methoden
- join(): Warten, bis der Thread beendet ist.
- detach(): Den Thread in den Hintergrund versetzen und nicht mehr auf sein Ende warten.
- joinable(): Prüfen, ob der Thread gejoint oder detached werden kann.
std::mutex
Die Klasse std::mutex wird verwendet, um den Zugriff auf gemeinsam genutzte Ressourcen zu synchronisieren.
Beispiel
#include <thread>
#include <mutex>
std::mutex mtx; // Globales Mutex-Objekt erstellen
int shared_resource = 0; // Gemeinsam genutzte Ressource
// Thread-Funktion
void increment() {
std::lock_guard<std::mutex> lock(mtx); // Sperren, um Threadsicherheit zu gewährleisten
++shared_resource;
std::cout << "shared_resource inkrementiert auf " << shared_resource << std::endl;
// Die Sperre wird automatisch freigegeben, wenn lock_guard den Gültigkeitsbereich verlässt
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join(); // Warten, bis Thread t1 beendet ist
t2.join(); // Warten, bis Thread t2 beendet ist
std::cout << "Endgültiger Wert von shared_resource: " << shared_resource << std::endl;
return 0;
}
std::lock_guard
std::lock_guard ist ein Lock-Manager im RAII-Stil, mit dem der Lebenszyklus der Sperre automatisch verwaltet wird.
Beispiel
#include <thread>
#include <mutex>
std::mutex mtx;
void print_thread_id(int id) {
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Thread ID: " << id << std::endl;
}
int main() {
std::thread t1(print_thread_id, 1);
std::thread t2(print_thread_id, 2);
t1.join();
t2.join();
return 0;
}
std::unique_lock
std::unique_lock bietet eine flexiblere Sperrverwaltung als std::lock_guard.
Beispiel
#include <thread>
#include <mutex>
std::mutex mtx;
void print_thread_id(int id) {
std::unique_lock<std::mutex> lock(mtx);
std::cout << "Thread ID: " << id << std::endl;
lock.unlock(); // Kann manuell entsperrt werden
// ... weitere Operationen
}
int main() {
std::thread t1(print_thread_id, 1);
std::thread t2(print_thread_id, 2);
t1.join();
t2.join();
return 0;
}
std::condition_variable
std::condition_variable wird zum Warten und Benachrichtigen zwischen Threads verwendet.
Beispiel
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id(int id) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; });
std::cout << "Thread ID: " << id << std::endl;
}
void set_ready() {
std::unique_lock<std::mutex> lock(mtx);
ready = true;
cv.notify_all();
}
int main() {
std::thread t1(print_id, 1);
std::thread t2(print_id, 2);
std::this_thread::sleep_for(std::chrono::seconds(1));
set_ready();
t1.join();
t2.join();
return 0;
}
std::future und std::promise
std::future und std::promise werden verwendet, um Ergebnisse zwischen Threads zu übergeben.
Beispiel
#include <thread>
#include <future>
void calculate_square(std::promise<int> && p, int x) {
p.set_value(x * x);
}
int main() {
std::promise<int> p;
std::future<int> f = p.get_future();
std::thread t(calculate_square, std::move(p), 5);
std::cout << "Square: " << f.get() << std::endl;
t.join();
return 0;
}
std::async
std::async wird verwendet, um asynchrone Aufgaben zu starten und gibt ein std::future zurück.
Beispiel
#include <future>
int calculate_square(int x) {
return x * x;
}
int main() {
std::future<int> result = std::async(calculate_square, 5);
std::cout << "Square: " << result.get() << std::endl;
return 0;
}
C++'s<thread>Die Bibliothek bietet Entwicklern leistungsstarke Multithreading-Unterstützung. Durch die Einführung in diesem Artikel sollten wir in der Lage sein, die grundlegenden Konzepte von Threads zu verstehen und zu lernen, wie man<thread>die Bibliothek verwendet, um Threads zu erstellen und zu verwalten. In der tatsächlichen Entwicklung kann eine sinnvolle Nutzung von Multithreading die Programmleistung und Reaktionsfähigkeit erheblich verbessern.