在C++并发编程中,线程同步是确保多个线程之间正确协作的关键。本文将聚焦于线程同步机制中的锁,详细探讨互斥锁、条件变量等锁的使用技巧,以帮助开发者在并发编程中更好地处理线程安全问题。
互斥锁是最基本也是最常用的线程同步机制之一。它用于保护共享资源,确保同一时间只有一个线程可以访问该资源。
在C++11中,`std::mutex` 提供了便捷的互斥锁功能。下面是一个简单的示例:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
int counter = 0;
void increment() {
for (int i = 0; i < 1000; ++i) {
std::lock_guard lock(mtx); // 自动加锁和解锁
++counter;
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Counter: " << counter << std::endl;
return 0;
}
在这个示例中,`std::lock_guard` 是一个简单的RAII(Resource Acquisition Is Initialization)封装,它在构造时自动加锁,在析构时自动解锁,从而简化了锁的管理。
对于更复杂的场景,可以使用 `std::unique_lock`,它提供了更灵活的加锁和解锁控制。例如,可以手动解锁并稍后重新加锁:
std::unique_lock lock(mtx);
// 进行一些操作
lock.unlock();
// 进行其他操作
lock.lock();
// 继续操作
条件变量用于在线程之间同步某个条件。一个线程可以等待某个条件成立,而另一个线程可以在条件满足时通知等待的线程。
下面是一个使用条件变量的简单示例:
#include <iostream>
#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 lck(mtx);
while (!ready) cv.wait(lck);
// 当 ready 为 true 时,继续执行
std::cout << "Thread " << id << '\n';
}
void go() {
std::unique_lock lck(mtx);
ready = true;
cv.notify_all(); // 通知所有等待的线程
}
int main() {
std::thread threads[10];
for (int i = 0; i < 10; ++i)
threads[i] = std::thread(print_id, i);
std::cout << "10 threads ready to race...\n";
go(); // 让所有线程继续执行
for (auto& th : threads) th.join();
return 0;
}
在这个示例中,条件变量 `cv` 与互斥锁 `mtx` 一起使用,以确保线程在 `ready` 条件成立时才能继续执行。
本文深入探讨了C++并发编程中的线程同步机制,特别是互斥锁和条件变量的使用技巧。通过理解这些机制,开发者可以更好地处理并发编程中的线程安全问题,编写出更加健壮和高效的代码。