Analisis isu konkurensi dalam pengaturcaraan berbilang benang C++
Dengan pembangunan berterusan perkakasan komputer, pemproses berbilang teras telah menjadi arus perdana. Dalam kes ini, menggunakan multi-threading untuk menggunakan sepenuhnya prestasi pemproses berbilang teras telah menjadi teknologi penting dalam pembangunan program. Walau bagaimanapun, dalam pengaturcaraan berbilang benang, disebabkan oleh operasi serentak antara berbilang benang, beberapa masalah sering berlaku. Artikel ini akan menggunakan contoh kod khusus untuk menganalisis isu konkurensi dalam pengaturcaraan berbilang benang C++.
Apabila berbilang rangkaian mengakses dan mengubah suai sumber dikongsi pada masa yang sama, mudah menyebabkan persaingan data. Keputusan perlumbaan data tidak dapat diramalkan dan boleh menyebabkan ralat program. Berikut ialah kod sampel mudah:
#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; }
Dalam kod di atas, dua utas secara serentak menambah kiraan. Memandangkan dua utas mengakses dan mengubah suai kiraan pada masa yang sama, persaingan data mungkin berlaku. Hasil daripada menjalankan kod di atas tidak ditentukan dan mungkin berbeza setiap kali ia dijalankan.
Penyelesaian kepada masalah ini adalah dengan memperkenalkan kunci mutex atau operasi atom. Tingkatkan kod di atas:
#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; }
Dalam kod yang dipertingkatkan, kunci mutex mtx
diperkenalkan melalui std::lock_guard<std::mutex>
Kunci dan buka kunci mutex secara automatik . Dengan cara ini, apabila mengubah suai count
dalam fungsi increment
, ia akan dikunci terlebih dahulu untuk memastikan hanya satu utas boleh mengakses dan mengubah suai sumber yang dikongsi pada masa yang sama. Menjalankan kod yang dipertingkatkan memberikan hasil yang betul. 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
Satu lagi masalah konkurensi biasa ialah kebuntuan. Kebuntuan ialah situasi di mana dua atau lebih utas tidak dapat meneruskan pelaksanaan sementara menunggu satu sama lain melepaskan kunci. Berikut ialah kod contoh kebuntuan mudah:
rrreee🎜Dalam kod di atas, dua utasthread1
dan thread2
bertanggungjawab untuk mtx1
dan mtx2 melakukan penguncian. Tetapi selepas mengunci, mereka cuba mengunci kunci lain, mengakibatkan keadaan buntu menunggu antara satu sama lain. Ini akan menghalang program daripada diteruskan. 🎜🎜Cara untuk menyelesaikan masalah kebuntuan adalah dengan menyatukan susunan perolehan kunci. Iaitu, semua benang memperoleh kunci dalam susunan yang sama apabila memperoleh kunci. Ubah suai kod di atas: 🎜rrreee🎜Dalam kod yang dipertingkatkan, susunan pemerolehan kunci disatukan mtx1
diperoleh dahulu, dan kemudian mtx2
diperoleh. Dengan cara ini, berlakunya kebuntuan dapat dielakkan. 🎜🎜Ringkasan: 🎜🎜Isu konkurensi dalam pengaturcaraan berbilang benang adalah salah satu masalah biasa dalam pembangunan program. Artikel ini memperkenalkan secara ringkas persaingan sumber kongsi dan masalah kebuntuan dalam masalah konkurensi melalui contoh kod tertentu dan menyediakan penyelesaian yang sepadan. Dalam pengaturcaraan sebenar, kita perlu mempunyai pemahaman yang lebih mendalam tentang prinsip dan teknik pengaturcaraan berbilang benang untuk mengelakkan masalah konkurensi dan memastikan ketepatan dan kestabilan operasi program. 🎜Atas ialah kandungan terperinci Analisis isu konkurensi dalam pengaturcaraan berbilang benang C++. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!