在C++中设计线程安全的类需要遵循以下核心原则和技术实现:
1. 基本原则
- 临界资源全保护:对所有可能被并发访问的成员变量进行同步控制
- 接口原子化:确保每个公共成员函数的操作具有原子性
- 避免隐性共享:防止通过返回值/参数暴露内部数据引用
- 异常安全:保证锁机制在异常发生时仍能正确释放
2. 标准实现模式
#include <mutex>
#include <vector>
class ThreadSafeVector {
public:
void push(int value) {
std::lock_guard<std::mutex> lock(mtx_);
data_.push_back(value);
}
int at(size_t index) const {
std::lock_guard<std::mutex> lock(mtx_);
if(index >= data_.size()) throw std::out_of_range("");
return data_[index];
}
size_t size() const {
std::lock_guard<std::mutex> lock(mtx_);
return data_.size();
}
private:
mutable std::mutex mtx_; // mutable允许const函数加锁
std::vector<int> data_;
};
3. 高级优化技术
3.1 细粒度锁
class BankAccount {
public:
void transfer(double amount, BankAccount& to) {
std::unique_lock<std::mutex> lock1(mtx_, std::defer_lock);
std::unique_lock<std::mutex> lock2(to.mtx_, std::defer_lock);
std::lock(lock1, lock2); // 避免死锁
balance_ -= amount;
to.balance_ += amount;
}
private:
std::mutex mtx_;
double balance_ = 0;
};
3.2 读写锁(C++17+)
#include <shared_mutex>
class ConfigManager {
public:
std::string getConfig(const std::string& key) const {
std::shared_lock lock(rw_mtx_); // 共享读锁
return configs_.at(key);
}
void updateConfig(const std::string& key, const std::string& value) {
std::unique_lock lock(rw_mtx_); // 独占写锁
configs_[key] = value;
}
private:
mutable std::shared_mutex rw_mtx_;
std::unordered_map<std::string, std::string> configs_;
};
4. 关键注意事项
返回值陷阱:
// 危险:返回内部指针
const int* unsafeGetPtr() const {
std::lock_guard lock(mtx_);
return &data_; // 锁释放后指针可能失效
}
// 安全:返回副本
std::vector<int> safeGetCopy() const {
std::lock_guard lock(mtx_);
return data_;
}
构造/析构安全:
- 构造函数不需要同步(对象尚未完全创建)
- 析构函数需确保无其他线程正在访问对象
移动语义处理:
class SafeObject {
public:
SafeObject(SafeObject&& other) noexcept {
std::lock_guard lock1(mtx_);
std::lock_guard lock2(other.mtx_);
data_ = std::move(other.data_);
}
};
5. 验证方法
- 静态分析:使用Clang ThreadSanitizer
- 压力测试:
void concurrent_test() {
ThreadSafeVector vec;
std::vector<std::thread> threads;
for(int i=0; i<10; ++i){
threads.emplace_back([&vec, i](){
for(int j=0; j<1000; ++j){
vec.push(i*1000 + j);
}
});
}
for(auto& t : threads) t.join();
assert(vec.size() == 10000);
}
6. 设计模式选择
模式 | 适用场景 | 性能影响 |
---|---|---|
全局互斥锁 | 简单数据结构/低频操作 | 中等 |
读写锁 | 读多写少场景 | 较低 |
无锁编程 | 高性能关键路径 | 最低 |
分段锁 | 大规模哈希表等结构 | 低 |