Bibliothèque de multithreading C++<thread>
C++11 a introduit la prise en charge du multithreading, grâce à<thread>la bibliothèque, les développeurs peuvent facilement implémenter le traitement parallèle dans les programmes.
Cet article présentera<thread>Les concepts de base, les définitions, la syntaxe de la bibliothèque, ainsi que la manière de l'utiliser pour créer et gérer des threads.
Un thread est la plus petite unité d'exécution d'un programme et la plus petite unité que le système d'exploitation peut planifier pour le calcul.
Dans les programmes multithread, plusieurs threads peuvent s'exécuter en parallèle, ce qui améliore l'efficacité d'exécution du programme.
C++ <thread>Aperçu de la bibliothèque
<thread>La bibliothèque fait partie de la bibliothèque standard C++, fournissant les fonctionnalités de base pour créer et gérer des threads. Elle comprend les composants clés suivants :
std::thread: Représente un thread ; il peut créer, démarrer, attendre et détruire des threads.std::this_thread: Fournit certaines fonctions membres statiques pour manipuler le thread courant.std::thread::id: L'identifiant unique du thread.
Création de threads
Pour créer un thread, vous devez instancierstd::threadclasse, et passer un objet appelable (fonction, expression lambda ou fonction membre d'un objet) en argument.
Exemple
#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);
}
Démarrage des threads
Créezstd::threadAprès l'objet, le thread commencera immédiatement à s'exécuter ; vous pouvez appelerjoin()la méthode pour attendre que le thread se termine.
t1.join(); t2.join();
Attendre que le thread se termine
join()la méthode bloquera le thread actuel jusqu'à ce que le thread appelé termine son exécution.
Destruction des threads
Lorsque le thread a terminé son exécution, vous pouvez utiliserdetach()la méthode pour détacher le thread, ou laisserstd::threadl'objet sortir de sa portée et être détruit automatiquement.
t1.detach(); // 线程将继续运行,但无法再被 join ou detach
Exemple : Utilisation de<thread>Créer du calcul parallèle
Voici un exemple utilisant<thread>Exemple de calcul parallèle implémenté avec la bibliothèque, calculant la somme de deux nombres.
Exemple
#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 << "Somme : " << sum << std::endl; // Résultat de sortie : Somme : 30
}
Le résultat de sortie est:
Sum: 30
Dans l'exemple suivant, nous allons créer deux threads, dont chacun exécute une fonction simple qui affiche un message et dort pendant un moment :
Exemple
#include <thread>
#include <chrono>
// Fonction simple, exécutée dans un thread
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() {
// Créer deux threads et exécuter la fonction print_message
std::thread t1(print_message, "Hello from thread 1", 1000);
std::thread t2(print_message, "Hello from thread 2", 500);
// Attendre que le thread t1 se termine
if (t1.joinable()) {
t1.join();
}
// Attendre que le thread t2 se termine
if (t2.joinable()) {
t2.join();
}
std::cout << "Main thread finished." << std::endl;
return 0;
}
Le résultat de sortie est:
Hello from thread 2 Hello from thread 1 Main thread finished.
Notes
- Sécurité des threads : Dans un environnement multithread, les ressources partagées nécessitent un accès synchronisé pour éviter les courses de données.
- Cycle de vie des threads : Assurez-vous que l'objet thread est correctement géré après la fin de l'exécution du thread afin d'éviter les fuites de ressources.
Classes et fonctions
<thread>La bibliothèque contient une série de classes et de fonctions pour créer, gérer et synchroniser des threads.
Ce qui suit concerne C++<thread>Introduction détaillée à la bibliothèque :
Principaux composants
- std::thread
- std::mutex
- std::lock_guard
- std::unique_lock
- std::condition_variable
- std::future et std::promise
- std::async
std::thread
La classe std::thread est utilisée pour créer et gérer des threads.
Exemple
#include <thread>
void print_hello() {
std::cout << "Bonjour depuis le thread !" << std::endl;
}
int main() {
std::thread t(print_hello);
t.join(); // Attendre que le thread t se termine
return 0;
}
Méthodes importantes
- join(): Attendre la fin du thread.
- detach(): placer le thread en arrière-plan et ne plus l'attendre.
- joinable(): vérifier si le thread peut être joint ou détaché.
std::mutex
La classe std::mutex est utilisée pour synchroniser l'accès aux ressources partagées.
Exemple
#include <thread>
#include <mutex>
std::mutex mtx; // Créer un objet mutex global
int shared_resource = 0; // Ressource partagée
// Fonction de thread
void increment() {
std::lock_guard<std::mutex> lock(mtx); // Verrouiller pour garantir la sécurité des threads
++shared_resource;
std::cout << "shared_resource incrémenté à " << shared_resource << std::endl;
// le verrou est automatiquement libéré lorsque lock_guard sort de sa portée
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join(); // Attendre la fin du thread t1
t2.join(); // Attendre la fin du thread t2
std::cout << "Valeur finale de shared_resource : " << shared_resource << std::endl;
return 0;
}
std::lock_guard
std::lock_guard est un gestionnaire de verrou de style RAII utilisé pour gérer automatiquement le cycle de vie du verrou.
Exemple
#include <thread>
#include <mutex>
std::mutex mtx;
void print_thread_id(int id) {
std::lock_guard<std::mutex> lock(mtx);
std::cout << "ID du thread : " << 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 offre une gestion des verrous plus flexible que std::lock_guard.
Exemple
#include <thread>
#include <mutex>
std::mutex mtx;
void print_thread_id(int id) {
std::unique_lock<std::mutex> lock(mtx);
std::cout << "ID du thread : " << id << std::endl;
lock.unlock(); // Peut être déverrouillé manuellement
// ... autres opérations
}
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 est utilisé pour l'attente et la notification entre les threads.
Exemple
#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 << "ID du thread : " << 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 et std::promise
std::future et std::promise sont utilisés pour transmettre des résultats entre les threads.
Exemple
#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 est utilisé pour démarrer des tâches asynchrones et renvoie un std::future.
Exemple
#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>La bibliothèque offre aux développeurs un puissant support de multithreading. Grâce à l'introduction de cet article, nous devrions être en mesure de comprendre les concepts de base des threads et d'apprendre à utiliser<thread>la bibliothèque pour créer et gérer des threads. Dans le développement réel, une utilisation raisonnable du multithreading peut considérablement améliorer les performances et la réactivité du programme.