Bibliothèque standard C++<mutex>
Dans la programmation multithread, il est crucial de garantir la cohérence des données et la sécurité des threads.
La bibliothèque standard C++ fournit un ensemble riche de primitives de synchronisation utilisées pour contrôler l'accès aux ressources partagées.
Dans la bibliothèque standard C++,<mutex>Le fichier d'en-tête fournit un ensemble d'outils pour mettre en œuvre la synchronisation et l'exclusion mutuelle entre les threads dans les programmes multithread.
<mutex>Le fichier d'en-tête a été introduit en C++11 et contient des classes et des fonctions pour les verrous mutex. Un verrou mutex est un mécanisme de synchronisation utilisé pour empêcher plusieurs threads d'accéder aux ressources partagées en même temps.
Un mutex est une primitive de synchronisation utilisée pour contrôler l'accès aux ressources partagées. Lorsqu'un thread doit accéder à une ressource partagée, il tente de verrouiller le mutex. Si le mutex a déjà été verrouillé par un autre thread, le thread demandeur sera bloqué jusqu'à ce que le mutex soit libéré.
Syntaxe de base
En C++,<mutex>Le fichier d'en-tête fournit les principales classes suivantes :
std::mutex: Mutex de base.std::recursive_mutex: Verrou mutex récursif, permettant au même thread de verrouiller plusieurs fois.std::timed_mutex: Mutex avec fonctionnalité de délai d'attente.std::recursive_timed_mutex: Mutex récursif avec fonctionnalité de délai d'attente.
Exemple
1. Utilisationstd::mutex
Ce qui suit est un exemple simple montrant comment utiliser en C++std::mutexpour synchroniser l'accès aux ressources partagées.
Exemple
#include <thread>
#include <mutex>
std::mutex mtx; // Verrou mutex global
int shared_resource = 0;
void increment() {
for (int i = 0; i < 10000; ++i) {
mtx.lock(); // Verrouiller le mutex
++shared_resource;
mtx.unlock(); // Déverrouiller le mutex
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Valeur finale de shared_resource : " << shared_resource << std::endl;
return 0;
}
Résultat de sortie :
Final value of shared_resource: 20000
2. Utilisationstd::recursive_mutex
Un verrou mutex récursif permet au même thread de verrouiller le même mutex plusieurs fois. Ce qui suit est un exemple utilisantstd::recursive_mutexExemple.
Exemple
#include <thread>
#include <mutex>
std::recursive_mutex rmtx; // Créer un objet mutex récursif
int shared_resource = 0; // Ressource partagée
// Fonction récursive
void recursive_increment(int count) {
if (count <= 0) return;
std::lock_guard<std::recursive_mutex> lock(rmtx); // Verrouiller pour garantir la sécurité des threads
++shared_resource;
std::cout << "shared_resource incrémenté à " << shared_resource << " (count = " << count << ")" << std::endl;
// Appel récursif
recursive_increment(count - 1);
}
int main() {
std::thread t1(recursive_increment, 3); // Le thread t1 exécute recursive_increment(3)
std::thread t2(recursive_increment, 3); // Le thread t2 exécute recursive_increment(3)
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;
}
Résultat de sortie :
Incremented shared_resource to 1 (count = 3) Incremented shared_resource to 2 (count = 2) Incremented shared_resource to 3 (count = 1) Incremented shared_resource to 4 (count = 0) Incremented shared_resource to 5 (count = 3) Incremented shared_resource to 6 (count = 2) Incremented shared_resource to 7 (count = 1) Incremented shared_resource to 8 (count = 0) Final value of shared_resource: 8
Analyse du code :
Créez
std::recursive_mutexObject:std::recursive_mutex rmtx;Est un mutex récursif qui permet au même thread d'acquérir le verrou plusieurs fois.Ressource partagée:
int shared_resource = 0;est une ressource à laquelle plusieurs threads accèdent simultanément.Fonction récursive
recursive_increment:- Utilisation
std::lock_guard<std::recursive_mutex>PairrmtxVerrou. Comme un mutex récursif est utilisé, le même thread peut acquérir le verrou plusieurs fois. - Via
++shared_resourceAugmente la valeur de la ressource partagée. - La fonction s'appelle elle-même récursivement, ce qui montre comment une fonction récursive fonctionne en toute sécurité lorsqu'elle est verrouillée plusieurs fois.
- Utilisation
Création et exécution de threads:
std::thread t1(recursive_increment, 3);etstd::thread t2(recursive_increment, 3);Deux threads sont créés séparément, et les deux vont s'exécuterrecursive_increment(3)。t1.join()ett2.join()Attend que deux threads terminent leur exécution.
Notes
- Veillez à ce qu'après chaque acquisition d'un verrou mutex, une opération de déverrouillage soit effectuée pour éviter un interblocage.
- Utilisation
std::lock_guardoustd::unique_lockPeut gérer automatiquement le verrouillage et le déverrouillage des verrous mutex, ce qui réduit la possibilité d'erreurs. - Évitez d'appeler des fonctions susceptibles de lever des exceptions tout en détenant un verrou mutex, car cela peut conduire à un interblocage.
<mutex>Est un fichier d'en-tête très important de la bibliothèque standard C++, fournissant des mécanismes de synchronisation de base pour la programmation multithread. En utilisant des verrous mutex, nous pouvons garantir que l'accès aux ressources partagées est sûr, évitant ainsi les courses de données et les problèmes d'incohérence.
Plus d'informations
1. std::mutex
Fournit un mutex de base pour garantir qu'un seul thread peut accéder aux ressources partagées en même temps.
Exemple
std::mutex mtx;
void thread_function() {
std::lock_guard<std::mutex> lock(mtx);
// Accéder à la ressource partagée
}
2. std::recursive_mutex
Permet au même thread d'acquérir le verrou plusieurs fois sans provoquer d'interblocage, ce qui est particulièrement utile pour les fonctions récursives.
Exemple
std::recursive_mutex rmtx;
void recursive_function(int count) {
if (count <= 0) return;
std::lock_guard<std::recursive_mutex> lock(rmtx);
// Appel récursif
recursive_function(count - 1);
}
3. std::timed_mutex
Fournit un mutex temporisé qui peut définir un délai d'attente lors de la tentative d'acquisition du verrou.
Exemple
#include <chrono>
std::timed_mutex tm;
void try_lock_for_example() {
if (tm.try_lock_for(std::chrono::seconds(1))) {
// Verrou acquis avec succès
tm.unlock();
} else {
// Échec de l'acquisition du verrou
}
}
4. std::recursive_timed_mutex
Hérité de std::timed_mutex, permettant au même thread d'acquérir le verrou plusieurs fois tout en prenant également en charge la fonctionnalité de temporisation.
Exemple
#include <chrono>
std::recursive_timed_mutex rtm;
void recursive_timed_function(int count) {
if (count <= 0) return;
if (rtm.try_lock_for(std::chrono::seconds(1))) {
// Verrou acquis avec succès
recursive_timed_function(count - 1);
rtm.unlock();
} else {
// Échec de l'acquisition du verrou
}
}
5. std::lock_guard
Une enveloppe qui gère automatiquement les verrous std::mutex, en utilisant le style RAII pour garantir que le verrou est automatiquement libéré à la fin de la portée.
Exemple
std::mutex mtx;
void function() {
std::lock_guard<std::mutex> lock(mtx);
// Accéder à la ressource partagée
}
6. std::unique_lock
Fournit une gestion plus flexible des verrous que std::lock_guard, permettant la libération et la réacquisition manuelles des verrous, et prenant également en charge le verrouillage temporisé.
Exemple
#include <chrono>
std::mutex mtx;
void function() {
std::unique_lock<std::mutex> lock(mtx);
// Accéder à la ressource partagée
// Peut libérer manuellement le verrou
lock.unlock();
// Peut réacquérir le verrou
lock.lock();
// Peut effectuer un verrouillage temporisé
if (lock.try_lock_for(std::chrono::seconds(1))) {
// Verrou acquis avec succès
}
}
7. std::adopt_lock_t
Type d'indicateur utilisé pour spécifier que std::unique_lock adopte un verrou existant.
Exemple
std::unique_lock<std::mutex> lock(mtx, std::adopt_lock);
8. std::defer_lock_t
Fonction : type d'indicateur utilisé pour un verrouillage différé, et aucun verrou n'est acquis lors de l'initialisation.
Exemple
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
// On peut appeler lock.lock() à un moment ultérieur
9. std::try_to_lock_t
Type d'indicateur, utilisé pour tenter un verrouillage sans blocage.
Exemple
std::unique_lock<std::mutex> lock1(mtx1, std::try_to_lock);
std::unique_lock<std::mutex> lock2(mtx2, std::try_to_lock);
if (lock1 && lock2) {
// Les deux verrous ont été acquis avec succès
}