线程安全
定义
线程安全(Thread Safety)是指多线程环境下,多个线程同时访问和操作同一资源时,程序的行为仍然是正确的,即不会因为多线程的并发操作而导致数据不一致或程序崩溃。
如何保证线程安全
确保线程安全通常涉及以下几种常见的方法和技术:
1. 互斥锁(Mutex)
互斥锁用于保证在同一时刻只有一个线程可以访问共享资源。
std::mutex: C++ 标准库中的互斥锁。std::lock_guard 和 std::unique_lock: 用于在作用域内自动管理互斥锁的加锁和解锁。
示例:
#include
#include
#include
std::mutex mtx;
int counter = 0;
void increment() {
std::lock_guard
++counter;
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Counter: " << counter << std::endl;
return 0;
}
2. 读写锁(Read-Write Lock)
读写锁允许多个线程同时读取共享资源,但在写操作时,只有一个线程可以进行写操作,并且此时其他读操作和写操作都会被阻塞。
std::shared_mutex: C++17 引入的共享互斥锁。std::shared_lock: 用于管理读锁。
示例:
#include
#include
#include
std::shared_mutex rw_mtx;
int shared_data = 0;
void read() {
std::shared_lock
std::cout << "Read: " << shared_data << std::endl;
}
void write() {
std::unique_lock
shared_data++;
std::cout << "Write: " << shared_data << std::endl;
}
int main() {
std::thread t1(read);
std::thread t2(write);
t1.join();
t2.join();
return 0;
}
3. 原子操作(Atomic Operations)
原子操作提供了一种不用显式锁的线程安全操作方式,往往用于简单的计数器或标志位。
std::atomic: C++ 标准库中的原子类型和操作。
示例:
#include
#include
#include
std::atomic
void increment() {
counter++;
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Counter: " << counter << std::endl;
return 0;
}
4. 条件变量(Condition Variable)
条件变量用于在线程间进行复杂的同步,通常和互斥锁一起使用。
std::condition_variable: C++ 标准库中的条件变量。
示例:
#include
#include
#include
#include
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id(int id) {
std::unique_lock
cv.wait(lock, [] { return ready; });
std::cout << "Thread " << id << std::endl;
}
void set_ready() {
std::lock_guard
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::this_thread::sleep_for(std::chrono::seconds(1));
set_ready();
for (auto& th : threads) {
th.join();
}
return 0;
}
5. 线程局部存储(Thread-Local Storage)
使用线程局部存储可以使每个线程拥有自己独立的变量副本,避免共享资源引起的竞争。
thread_local: C++11 引入的线程局部存储关键字。
示例:
#include
#include
thread_local int local_counter = 0;
void increment() {
local_counter++;
std::cout << "Local Counter: " << local_counter << std::endl;
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
return 0;
}