【欢迎关注编码小哥,学习更多实用的编程方法和技巧】
1、互斥锁基本使用
#include <mutex>
#include <thread>
#include <iostream>
class Counter {
private:
int value = 0;
std::mutex mtx;
public:
// 使用互斥锁保护临界区
void increment() {
// 传统加锁方式
mtx.lock();
value++;
mtx.unlock();
}
// 推荐使用RAII锁
void incrementSafe() {
std::lock_guard<std::mutex> lock(mtx);
value++;
}
int getValue() {
std::lock_guard<std::mutex> lock(mtx);
return value;
}
};
2、 读写锁
#include <shared_mutex>
class ThreadSafeCache {
private:
std::unordered_map<int, std::string> cache;
mutable std::shared_mutex mtx;
public:
// 写操作
void put(int key, const std::string& value) {
std::unique_lock<std::shared_mutex> lock(mtx);
cache[key] = value;
}
// 读操作
std::string get(int key) const {
std::shared_lock<std::shared_mutex> lock(mtx);
auto it = cache.find(key);
return (it != cache.end()) ? it->second : "";
}
};
3、 条件变量
#include <condition_variable>
#include <queue>
class ThreadSafeQueue {
private:
std::queue<int> queue;
std::mutex mtx;
std::condition_variable cv;
public:
void push(int value) {
{
std::lock_guard<std::mutex> lock(mtx);
queue.push(value);
}
cv.notify_one(); // 通知等待线程
}
int pop() {
std::unique_lock<std::mutex> lock(mtx);
// 等待直到队列非空
cv.wait(lock, [this]() {
return !queue.empty();
});
int value = queue.front();
queue.pop();
return value;
}
};
4、原子操作
#include <atomic>
class AtomicCounter {
private:
std::atomic<int> counter{0};
public:
void increment() {
// 原子自增
counter++;
}
int get() {
return counter.load(); // 原子读取
}
// 复杂原子操作
void complexOperation() {
counter.compare_exchange_weak(
expected, // 期望值
desired // 新值
);
}
};
5、死锁预防
class DeadlockPrevention {
private:
std::mutex mtx1, mtx2;
public:
void safeOperation() {
// 使用std::lock避免死锁
std::lock(mtx1, mtx2);
// RAII锁
std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
// 临界区代码
}
};
6、信号量
class Semaphore {
private:
std::mutex mtx;
std::condition_variable cv;
int count;
public:
explicit Semaphore(int initial = 0) : count(initial) {}
void wait() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [this] { return count > 0; });
--count;
}
void signal() {
std::unique_lock<std::mutex> lock(mtx);
++count;
cv.notify_one();
}
};
7、生产者、消费者模型
class ProducerConsumer {
private:
std::queue<int> queue;
std::mutex mtx;
std::condition_variable not_full;
std::condition_variable not_empty;
const size_t CAPACITY = 10;
public:
void produce(int value) {
std::unique_lock<std::mutex> lock(mtx);
// 等待队列不满
not_full.wait(lock, [this]{
return queue.size() < CAPACITY;
});
queue.push(value);
lock.unlock();
not_empty.notify_one();
}
int consume() {
std::unique_lock<std::mutex> lock(mtx);
// 等待队列非空
not_empty.wait(lock, [this]{
return !queue.empty();
});
int value = queue.front();
queue.pop();
lock.unlock();
not_full.notify_one();
return value;
}
};
8、性能优化
// 减少锁的粒度
class OptimizedCounter {
private:
// 使用更细粒度的锁
std::array<std::mutex, 16> locks;
std::array<int, 16> counters = {0};
public:
void increment(int index) {
// 根据索引选择特定锁
std::lock_guard<std::mutex> lock(locks[index % locks.size()]);
counters[index % counters.size()]++;
}
};
9、同步原语选择建议
- 互斥锁:简单的临界区保护
- 读写锁:读多写少场景
- 条件变量:线程间通信
- 原子操作:简单共享变量
- 信号量:资源受限场景
关键原则:
- 最小化锁的持有时间
- 避免嵌套锁
- 使用RAII管理锁
- 选择合适的同步原语
- 注意性能开销