Analyse des problèmes de concurrence dans la programmation multithread C++
Avec le développement continu du matériel informatique, les processeurs multicœurs sont devenus courants. Dans ce cas, l’utilisation du multithreading pour exploiter pleinement les performances des processeurs multicœurs est devenue une technologie importante dans le développement de programmes. Cependant, dans la programmation multithread, en raison d'opérations simultanées entre plusieurs threads, certains problèmes surviennent souvent. Ces problèmes sont appelés problèmes de concurrence. Cet article utilisera des exemples de code spécifiques pour analyser les problèmes de concurrence dans la programmation multithread C++.
Lorsque plusieurs threads accèdent et modifient des ressources partagées en même temps, il est facile de provoquer une concurrence sur les données. Les résultats des courses aux données sont imprévisibles et peuvent provoquer des erreurs de programme. Voici un exemple de code simple :
#include <iostream> #include <thread> int count = 0; void increment() { for (int i = 0; i < 100000; ++i) { count++; } } int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); std::cout << "count: " << count << std::endl; return 0; }
Dans le code ci-dessus, deux threads incrémentent simultanément le nombre. Étant donné que deux threads accèdent et modifient le nombre en même temps, une concurrence sur les données est susceptible de se produire. Le résultat de l'exécution du code ci-dessus n'est pas défini et peut être différent à chaque exécution.
La solution à ce problème est d'introduire des verrous mutex ou des opérations atomiques. Améliorez le code ci-dessus :
#include <iostream> #include <thread> #include <mutex> int count = 0; std::mutex mtx; void increment() { for (int i = 0; i < 100000; ++i) { std::lock_guard<std::mutex> lock(mtx); count++; } } int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); std::cout << "count: " << count << std::endl; return 0; }
Dans le code amélioré, un verrou mutex mtx
est introduit via std::lock_guard<std::mutex>
Verrouille et déverrouille automatiquement les verrous mutex . De cette façon, lors de la modification de count
dans la fonction increment
, il sera d'abord verrouillé pour garantir qu'un seul thread puisse accéder et modifier la ressource partagée en même temps. L'exécution du code amélioré donne des résultats corrects. mtx
,通过std::lock_guard<std::mutex>
来对互斥锁进行自动加锁和解锁。这样,在increment
函数中对count
进行修改时,会先加锁,保证同一时间只有一个线程能够访问和修改共享资源。运行改进后的代码,可以得到正确的结果。
另一个常见的并发问题是死锁。死锁是指两个或多个线程相互等待对方释放锁而无法继续执行的情况。以下是一个简单的死锁示例代码:
#include <iostream> #include <thread> #include <mutex> std::mutex mtx1, mtx2; void thread1() { std::lock_guard<std::mutex> lock1(mtx1); std::this_thread::sleep_for(std::chrono::seconds(1)); std::lock_guard<std::mutex> lock2(mtx2); std::cout << "Thread 1" << std::endl; } void thread2() { std::lock_guard<std::mutex> lock2(mtx2); std::this_thread::sleep_for(std::chrono::seconds(1)); std::lock_guard<std::mutex> lock1(mtx1); std::cout << "Thread 2" << std::endl; } int main() { std::thread t1(thread1); std::thread t2(thread2); t1.join(); t2.join(); return 0; }
上述代码中,thread1
和thread2
两个线程分别对mtx1
和mtx2
进行加锁。但是在加锁后,它们又试图对另一个锁进行加锁,从而形成了相互等待的死锁情况。这将导致程序无法继续执行。
解决死锁问题的方法是对锁的获取顺序进行统一。即,所有线程在获取锁的时候,都按照相同的顺序获取锁。修改上述代码:
void thread1() { std::lock_guard<std::mutex> lock1(mtx1); std::this_thread::sleep_for(std::chrono::seconds(1)); std::lock_guard<std::mutex> lock2(mtx2); std::cout << "Thread 1" << std::endl; } void thread2() { std::lock_guard<std::mutex> lock1(mtx1); std::this_thread::sleep_for(std::chrono::seconds(1)); std::lock_guard<std::mutex> lock2(mtx2); std::cout << "Thread 2" << std::endl; }
在改进后的代码中,对锁的获取顺序进行了统一,都是先获取mtx1
,再获取mtx2
Un autre problème de concurrence courant est l'impasse. Un blocage est une situation dans laquelle deux threads ou plus sont incapables de poursuivre l'exécution en attendant que l'autre libère le verrou. Ce qui suit est un exemple de code de blocage simple :
rrreee🎜Dans le code ci-dessus, les deux threadsthread1
et thread2
sont responsables de mtx1
et mtx2 effectue le verrouillage. Mais après le verrouillage, ils essaient de verrouiller un autre verrou, ce qui entraîne une situation d'impasse dans laquelle ils s'attendent mutuellement. Cela empêchera le programme de continuer. 🎜🎜La façon de résoudre le problème de blocage est d'unifier l'ordre d'acquisition du verrou. Autrement dit, tous les threads acquièrent les verrous dans le même ordre lors de l'acquisition des verrous. Modifiez le code ci-dessus : 🎜rrreee🎜Dans le code amélioré, l'ordre d'acquisition du verrou est unifié. mtx1
est acquis en premier, puis mtx2
est acquis. De cette manière, l’apparition d’un blocage est évitée. 🎜🎜Résumé : 🎜🎜Les problèmes de concurrence dans la programmation multithread sont l'un des problèmes courants dans le développement de programmes. Cet article présente brièvement les problèmes de concurrence sur les ressources partagées et de blocage dans les problèmes de concurrence à travers des exemples de code spécifiques, et fournit les solutions correspondantes. Dans la programmation réelle, nous devons avoir une compréhension plus approfondie des principes et techniques de la programmation multithread pour éviter les problèmes de concurrence et garantir l'exactitude et la stabilité du fonctionnement du programme. 🎜Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!