C Analysis of Concurrency Issues in Multi-Threaded Programming
With the continuous development of computer hardware, multi-core processors have become mainstream. In this case, using multi-threading to fully utilize the performance of multi-core processors has become an important technology in program development. However, in multi-threaded programming, due to concurrent operations between multiple threads, some problems often occur. These problems are called concurrency problems. This article will use specific code examples to analyze concurrency issues in C multi-threaded programming.
When multiple threads access and modify shared resources at the same time, it is easy to cause data competition. The results of data races are unpredictable and may cause program errors. The following is a simple sample code:
#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; }
In the above code, two threads concurrently increment the count. Since two threads access and modify count at the same time, data competition is likely to occur. The result of running the above code is undefined and may be different each time it is run.
The solution to this problem is to introduce a mutex lock or atomic operation. Improve the above code:
#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; }
In the improved code, a mutex lock mtx
is introduced, through std::lock_guard<std::mutex>
To automatically lock and unlock the mutex. In this way, when count
is modified in the increment
function, it will be locked first to ensure that only one thread can access and modify the shared resource at the same time. Running the improved code gives correct results.
Another common concurrency problem is deadlock. Deadlock is a situation where two or more threads are unable to continue execution while waiting for each other to release the lock. The following is a simple deadlock example code:
#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; }
In the above code, the two threads thread1
and thread2
are responsible for mtx1
and # respectively. ##mtx2 Lock. But after locking, they try to lock another lock, resulting in a deadlock situation of waiting for each other. This will prevent the program from continuing.
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 is acquired first, and then
mtx2 is acquired. In this way, the occurrence of deadlock is avoided.
The above is the detailed content of Analysis of concurrency issues in C++ multi-thread programming. For more information, please follow other related articles on the PHP Chinese website!