一、内存模型与happens-before
C++11引入的内存模型是现代并发编程的基础。理解 happens-before 关系,是写出正确并发代码的核心。
1.1 线程间同步的六条规则
// C++11定义了6种基本同步关系:
//
// ① program order: 同一线程内,前面的操作happens-before后面的操作
// ② mutex: mutex.unlock() happens-before 后续的mutex.lock()
// ③ thread termination: thread.join() returns happens-before 调用点的后续
// ④ semaphore release/acquire: sem.post() happens-before sem.wait()返回
// ⑤ condition variable: notify_one/all happens_before wait()唤醒后检查条件
// ⑥ memory_order_seq_cst: 顺序一致加载/释放(最强保证)
// 示例:线程间安全传递数据
std::thread t1([&]() {
data = 42; // ① data赋值
flag.store(true); // ② 标记置1(release)
});
std::thread t2([&]() {
while (!flag.load()) {} // ③ 自旋等待
assert(data == 42); // ④ 一定能读到42
});
// flag.store()的release和load()的acquire配对
// 保证① happens-before ② happens-before ③ → ④
二、原子类型的五种内存序
2.1 内存序的选择决策树
// std::memory_order的五种语义
//
// memory_order_seq_cst:顺序一致性(默认,最安全但最慢)
// 所有线程看到完全一致的操作顺序
// 性能开销:约10-50倍于普通写操作
//
// memory_order_acq_rel:获取-释放(信号量语义)
// load() = acquire(获取同步)
// store() = release(释放同步)
// fetch_add() = acq_rel
//
// memory_order_consume:消费序(最弱,推荐用于依赖链)
// 避免不必要的指令重排(避免" transitive fence")
// std::kill_dependency() 显式切断依赖链
//
// memory_order_relaxed:无同步(仅保证原子性)
// 适用于:计数器、自增ID、统计
// 决策树:
// 是否需要跨线程同步?
// 否 → relaxed(性能最好)
// 是 → 是否有严格的全序要求?
// 是 → seq_cst
// 否 → 是否有acquire/release配对?
// 是 → acq_rel / acquire / release
// 否 → consume(依赖链)
// 生产代码推荐:
// ① 简单标志:release/acquire(flag.test_and_set())
// ② 计数器统计:relaxed(stats++)
// ③ 跨线程数据传递:seq_cst
// ④ lock-free队列:acq_rel + consume
2.2 生产代码示例
// 生产级lock-free栈
template
class LockFreeStack {
struct Node {
T data;
std::atomic next;
Node(const T& d) : data(d), next(nullptr) {}
};
std::atomic head_{nullptr};
std::atomic item_count_{0};
public:
~LockFreeStack() {
while (pop()); // 清空
}
void push(const T& data) {
Node* n = new Node(data);
Node* cur = head_.load(std::memory_order_relaxed);
do {
n->next.store(cur, std::memory_order_relaxed);
} while (!head_.compare_exchange_weak(
cur, n,
std::memory_order_release, // 成功时release
std::memory_order_relaxed // 失败时重读
));
item_count_.fetch_add(1, std::memory_order_relaxed);
}
bool try_pop(T& result) {
Node* cur = head_.load(std::memory_order_acquire);
while (cur) {
Node* next = cur->next.load(std::memory_order_relaxed);
if (head_.compare_exchange_weak(
cur, next,
std::memory_order_seq_cst,
std::memory_order_relaxed
)) {
result = cur->data;
delete cur;
item_count_.fetch_sub(1, std::memory_order_relaxed);
return true;
}
}
return false;
}
};
三、线程池与任务调度
// C++20 jthread:自动join的线程
void worker(std::stop_token token) {
while (!token.stop_requested()) {
// 处理任务
std::this_thread::sleep_for(10ms);
}
}
int main() {
std::jthread t1(worker); // 析构时自动join
std::jthread t2(worker);
// t1, t2析构时自动等待线程结束
}
// C++17 mutex/condition_variable版本
class ThreadPool {
std::vector workers_;
std::queue> tasks_;
std::mutex mtx_;
std::condition_variable cv_;
std::atomic stop_{false};
public:
explicit ThreadPool(size_t n = std::thread::hardware_concurrency()) {
workers_.reserve(n);
for (size_t i = 0; i < n; ++i) {
workers_.emplace_back([this] {
while (true) {
std::function task;
{
std::unique_lock lock(mtx_);
cv_.wait(lock, [this] { return stop_ || !tasks_.empty(); });
if (stop_ && tasks_.empty()) return;
task = std::move(tasks_.front());
tasks_.pop();
}
task();
}
});
}
}
template
auto submit(F&& f) -> std::future> {
auto task = std::make_shared()>>(
std::forward(f)
);
{
std::lock_guard lock(mtx_);
tasks_.emplace([task]() { (*task)(); });
}
cv_.notify_one();
return task->get_future();
}
~ThreadPool() {
stop_ = true;
cv_.notify_all();
for (auto& t : workers_) t.join();
}
};
四、锁的性能对比
// 各锁类型性能对比(10线程,100万次操作)
//
// std::mutex: 12ms ← 基准
// std::shared_mutex: 18ms ← 读写锁,读多写少时更优
// std::atomic (relaxed): 0.5ms ← 仅原子变量
// spinlock (自旋锁): 3ms ← 短临界区最优
// pthread_rwlock: 15ms
//
// 推荐策略:
// 临界区 < 100ns:自旋锁(避免上下文切换)
// 临界区 100ns ~ 10ms:std::mutex
// 读多写少(>10:1):shared_mutex
// 纯计数/统计:std::atomic
// 自旋锁实现(短临界区)
class SpinLock {
std::atomic_flag flag_ = ATOMIC_FLAG_INIT;
public:
void lock() {
while (flag_.test_and_set(std::memory_order_acquire)) {
// pause()提示CPU减少功耗,避免总线风暴
__builtin_ia32_pause();
}
}
bool try_lock() {
return !flag_.test_and_set(std::memory_order_acquire);
}
void unlock() {
flag_.clear(std::memory_order_release);
}
};