一、C++ 并发编程的演进历程
1. 传统多线程编程的困境
在 C++11 之前,开发者依赖操作系统 API(如 Windows 线程或 POSIX 线程)进行并发编程,面临以下挑战:
- 平台依赖性:代码难以跨平台移植
- 资源管理复杂:手动创建 / 销毁线程,缺乏 RAII 机制
- 同步原语简陋:条件变量、互斥锁实现不一致
典型的 POSIX 线程示例:
#include <pthread.h>
void* thread_func(void* arg) {
// 线程执行逻辑
return nullptr;
}
int main() {
pthread_t thread;
pthread_create(&thread, nullptr, thread_func, nullptr);
pthread_join(thread, nullptr); // 等待线程结束
return 0;
}
2. C++11 的并发革命
C++11 标准库引入了<thread>、<mutex>、<condition_variable>等头文件,提供了标准化的并发编程工具:
- 线程管理:
std::thread类封装线程创建与销毁 - 同步原语:
std::mutex、std::lock_guard、std::condition_variable - 原子操作:
std::atomic模板类提供无锁编程支持
二、基础线程操作与管理
1. 线程的创建与启动
#include <iostream>
#include <thread>
void worker() {
std::cout << "Worker thread ID: " << std::this_thread::get_id() << std::endl;
}
int main() {
std::thread t(worker); // 创建并启动线程
// 主线程继续执行
std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;
t.join(); // 等待子线程完成
// t.detach(); // 分离线程,使其在后台运行
return 0;
}
2. 线程传参与返回值
#include <thread>
#include <future>
// 带参数的线程函数
void sum(int a, int b, std::promise<int>& result) {
result.set_value(a + b);
}
int main() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
std::thread t(sum, 3, 4, std::ref(prom));
t.join();
std::cout << "Sum: " << fut.get() << std::endl;
return 0;
}
3. 线程池的实现思路
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <future>
class ThreadPool {
public:
explicit ThreadPool(size_t num_threads) {
for (size_t i = 0; i < num_threads; ++i) {
workers.emplace_back([this] {
while (true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
if (this->stop && this->tasks.empty()) return;
task = std::move(this->tasks.front());
this->tasks.pop();
}
task();
}
});
}
}
~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
}
condition.notify_all();
for (std::thread& worker : workers) {
worker.join();
}
}
template<class F, class... Args>
auto enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type> {
using return_type = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared< std::packaged_task<return_type()> >(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(queue_mutex);
if (stop) throw std::runtime_error("enqueue on stopped ThreadPool");
tasks.emplace([task]() { (*task)(); });
}
condition.notify_one();
return res;
}
private:
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;
std::mutex queue_mutex;
std::condition_variable condition;
bool stop = false;
};
三、同步原语与线程安全
1. 互斥锁与锁守卫
#include <mutex>
class Counter {
private:
int value;
std::mutex mtx;
public:
void increment() {
std::lock_guard<std::mutex> lock(mtx);
++value; // 线程安全的自增操作
}
// 更灵活的锁管理
int get_value() const {
std::unique_lock<std::mutex> lock(mtx);
// 可以在此处解锁:lock.unlock();
return value;
}
};
2. 条件变量的使用
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker_thread() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; }); // 等待通知
// 执行任务...
}
int main() {
std::thread t(worker_thread);
// 准备数据...
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one(); // 通知工作线程
t.join();
return 0;
}
3. 读写锁(C++17)
#include <shared_mutex>
class DataCache {
private:
mutable std::shared_mutex rw_mutex;
std::map<std::string, std::string> cache;
public:
std::string read(const std::string& key) const {
std::shared_lock<std::shared_mutex> lock(rw_mutex); // 共享锁(读锁)
return cache.at(key);
}
void write(const std::string& key, const std::string& value) {
std::unique_lock<std::shared_mutex> lock(rw_mutex); // 排他锁(写锁)
cache[key] = value;
}
};
四、原子操作与无锁编程
1. 原子变量基础
#include <atomic>
std::atomic<int> counter(0);
void increment() {
counter.fetch_add(1, std::memory_order_relaxed);
// 等价于 counter++,但为原子操作
}
2. 内存序的选择
std::atomic<bool> ready(false);
int data = 0;
void producer() {
data = 100; // 1. 写入数据
ready.store(true, std::memory_order_release); // 2. 释放操作
}
void consumer() {
while (!ready.load(std::memory_order_acquire)); // 3. 获取操作
// 4. 此时保证能看到data=100
}
3. 无锁队列实现示例
#include <atomic>
template<typename T>
class LockFreeQueue {
private:
struct Node {
T data;
std::atomic<Node*> next;
Node(const T& value) : data(value), next(nullptr) {}
};
std::atomic<Node*> head;
std::atomic<Node*> tail;
public:
LockFreeQueue() : head(nullptr), tail(nullptr) {}
void enqueue(const T& value) {
Node* new_node = new Node(value);
Node* old_tail = tail.load();
while (!tail.compare_exchange_weak(old_tail, new_node)) {}
if (old_tail) old_tail->next = new_node;
else head = new_node;
}
bool dequeue(T& value) {
Node* old_head = head.load();
while (old_head) {
Node* next = old_head->next;
if (head.compare_exchange_weak(old_head, next)) {
value = old_head->data;
delete old_head;
return true;
}
}
return false;
}
};
五、C++20 协程:轻量级并发方案
1. 协程基础概念
- 暂停点:协程可在
co_await处暂停执行,保存状态 - 无栈协程:C++ 协程基于状态机实现,无需传统线程栈
- 返回类型:
std::task、generator等包装协程结果
2. 简单协程示例
#include <coroutine>
#include <iostream>
#include <future>
// 协程返回类型
template<typename T>
struct Task {
struct promise_type {
T value_;
Task get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_value(const T& value) { value_ = value; }
void unhandled_exception() {}
};
};
// 异步任务
Task<int> async_task() {
std::cout << "协程开始执行" << std::endl;
co_await std::suspend_always{}; // 暂停点
std::cout << "协程恢复执行" << std::endl;
co_return 42;
}
int main() {
auto task = async_task();
// 协程执行到第一个暂停点
std::cout << "主线程继续执行" << std::endl;
// 恢复协程执行(实际应用中通常由调度器完成)
return 0;
}
3. 协程的实际应用
// 异步文件读取协程
Task<std::string> read_file_async(const std::string& path) {
auto file = co_await open_file_async(path);
auto content = co_await read_all_async(file);
co_await close_file_async(file);
co_return content;
}
六、并发编程最佳实践
-
避免共享状态:
- 优先使用线程局部存储(
thread_local) - 通过消息传递而非共享内存通信(如使用线程安全队列)
- 优先使用线程局部存储(
-
细粒度锁设计:
- 减小锁的粒度,避免长时间持有锁
- 使用读写锁优化读多写少的场景
-
异常安全:
- 使用
std::lock_guard、std::unique_lock等 RAII 包装器 - 确保异常发生时资源能正确释放
- 使用
-
性能调优:
- 使用无锁数据结构减少线程竞争
- 避免不必要的同步操作,采用原子变量替代互斥锁
七、并发编程工具链
-
性能分析工具:
- Valgrind:检测内存泄漏和数据竞争
- perf:分析 CPU 性能瓶颈
- Thread Sanitizer:检测线程竞争问题
-
并发模式库:
- Intel TBB:提供并行算法和任务调度框架
- Folly:Facebook 开源的 C++ 扩展库,含多种并发组件
总结
现代 C++ 的并发编程能力已从早期的简陋实现发展为功能完备的体系:
- 线程管理:
std::thread提供跨平台线程操作 - 同步原语:
mutex、condition_variable等保障线程安全 - 原子操作:提供高效无锁编程支持
- 协程:轻量级并发方案,适用于高并发 IO 场景

被折叠的 条评论
为什么被折叠?



