【C++】C++11并发库
目录
一、std::thread:跨平台线程类
1.1 thread的基本使用
1.2 线程参数传递的注意事项
1.3 线程ID与this_thread命名空间
二、互斥锁:保护共享数据
2.1 std::mutex基础用法
2.2 定时互斥锁:std::timed_mutex
2.3 递归互斥锁:std::recursive_mutex
三、RAII锁管理:自动资源释放
3.1 std::lock_guard:简单锁管理
3.2 std::unique_lock:功能丰富的锁管理
3.3 多锁管理:std::lock与std::try_lock
四、条件变量:线程间同步
4.1 condition_variable的基本使用
4.2 经典案例:交替打印奇偶数
五、原子操作:无锁编程
5.1 std::atomic基础类型
5.2 CAS操作详解
5.3 内存顺序模型详解
5.4 原子标志与自旋锁实现
六、异步编程工具
6.1 std::future与std::promise
6.2 std::shared_future
6.3 std::async与启动策略
6.4 std::packaged_task
6.5 std::future_status
七、高级并发工具
7.1 std::call_once:一次性执行
7.2 无锁数据结构示例
八、总结
一、std::thread:跨平台线程类
1.1 thread的基本使用
C++11 的 std::thread 是对各系统线程 API(如 Linux 的 pthread、Windows 的 Thread)的面向对象封装,具有跨平台、面向对象、支持现代 C++ 特性等优点。
常用构造函数:
// 默认构造,不表示线程
thread() noexcept;
// 最重要的构造:传入可调用对象和参数
template <class Fn, class... Args>
explicit thread(Fn&& fn, Args&&... args);
// 移动构造
thread(thread&& x) noexcept;
// 禁止拷贝
thread(const thread&) = delete;
基础示例:
#include <iostream>
#include <thread>
#include <vector>
void print_range(int start, int end) {
for (int i = start; i < end; ++i) {
std::cout << std::this_thread::get_id() << ":" << i << "\n";
}
}
int main() {
// 创建两个线程
std::thread t1(print_range, 0, 5);
std::thread t2(print_range, 5, 10);
// 等待线程完成
t1.join();
t2.join();
return 0;
}
1.2 线程参数传递的注意事项
线程参数传递时需要注意引用传递的问题。由于 std::thread 内部会将参数打包成结构体,默认情况下会进行值拷贝。如果需要引用传递,必须使用 std::ref 包装。
#include <thread>
#include <functional>
void modify_value(int& value, int new_val) {
value = new_val;
}
int main() {
int value = 10;
// 错误:value会被拷贝,原value不会被修改
// std::thread t1(modify_value, value, 20);
// 正确:使用std::ref进行引用传递
std::thread t1(modify_value, std::ref(value), 20);
t1.join();
std::cout << "Value after modification: " << value << std::endl; // 输出20
return 0;
}
也可以使用 lambda 表达式捕获引用,避免参数传递问题:
int main() {
int value = 10;
auto lambda = [&value](int new_val) {
value = new_val;
};
std::thread t1(lambda, 20);
t1.join();
std::cout << "Value: " << value << std::endl; // 输出20
return 0;
}
1.3 线程ID与this_thread命名空间
std::this_thread 命名空间提供了对当前线程的控制:
#include <thread>
#include <chrono>
#include <iostream>
void thread_func() {
std::cout << "Thread ID: " << std::this_thread::get_id() << std::endl;
// 让出当前线程的时间片
std::this_thread::yield();
// 休眠1秒
std::this_thread::sleep_for(std::chrono::seconds(1));
// 休眠直到指定时间点
auto wake_time = std::chrono::system_clock::now() + std::chrono::seconds(2);
std::this_thread::sleep_until(wake_time);
}
int main() {
std::thread t(thread_func);
t.join();
return 0;
}
二、互斥锁:保护共享数据
2.1 std::mutex基础用法
std::mutex 是最基本的互斥锁,用于保护临界区资源,防止数据竞争。
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
std::mutex g_mutex;
int g_counter = 0;
void increment_counter(int n) {
for (int i = 0; i < n; ++i) {
g_mutex.lock(); // 加锁
++g_counter; // 临界区操作
g_mutex.unlock(); // 解锁
}
}
int main() {
std::vector<std::thread> threads;
// 创建4个线程同时增加计数器
for (int i = 0; i < 4; ++i) {
threads.emplace_back(increment_counter, 100000);
}
for (auto& t : threads) {
t.join();
}
std::cout << "Final counter: " << g_counter << std::endl; // 总是400000
return 0;
}
2.2 定时互斥锁:std::timed_mutex
std::timed_mutex 在 std::mutex 基础上增加了超时功能,可以避免无限期等待。
#include <thread>
#include <mutex>
#include <chrono>
std::timed_mutex g_timed_mutex;
void task_with_timeout(int id) {
// 尝试获取锁,最多等待100ms
if (g_timed_mutex.try_lock_for(std::chrono::milliseconds(100))) {
std::cout << "Thread " << id << " acquired lock\n";
std::this_thread::sleep_for(std::chrono::milliseconds(50));
g_timed_mutex.unlock();
} else {
std::cout << "Thread " << id << " failed to acquire lock\n";
}
}
2.3 递归互斥锁:std::recursive_mutex
std::recursive_mutex 允许同一线程多次获取锁,避免自死锁。
#include <mutex>
std::recursive_mutex g_recursive_mutex;
void recursive_function(int depth) {
if (depth <= 0) return;
g_recursive_mutex.lock();
std::cout << "Depth: " << depth << std::endl;
recursive_function(depth - 1); // 递归调用,需要递归锁
g_recursive_mutex.unlock();
}
三、RAII锁管理:自动资源释放
3.1 std::lock_guard:简单锁管理
std::lock_guard 采用 RAII 机制,构造时自动加锁,析构时自动解锁,确保异常安全。
#include <mutex>
#include <thread>
std::mutex g_mutex;
void safe_increment(int& counter, int n) {
for (int i = 0; i < n; ++i) {
std::lock_guard<std::mutex> lock(g_mutex); // 构造时加锁
++counter; // 临界区操作
// lock析构时自动解锁,即使发生异常也能保证解锁
}
}
// 手动实现lock_guard的原理
template<typename Mutex>
class SimpleLockGuard {
public:
explicit SimpleLockGuard(Mutex& mtx) : m_mutex(mtx) {
m_mutex.lock();
}
~SimpleLockGuard() {
m_mutex.unlock();
}
// 禁止拷贝
SimpleLockGuard(const SimpleLockGuard&) = delete;
SimpleLockGuard& operator=(const SimpleLockGuard&) = delete;
private:
Mutex& m_mutex;
};
3.2 std::unique_lock:功能丰富的锁管理
std::unique_lock 比 lock_guard 功能更丰富,支持延迟加锁、条件变量等高级特性。
构造方式:
std::mutex mtx;
// 1. 默认:立即加锁
std::unique_lock<std::mutex> lock1(mtx);
// 2. 延迟加锁:构造时不加锁,后续手动加锁
std::unique_lock<std::mutex> lock2(mtx, std::defer_lock);
// 3. 尝试加锁:构造时尝试加锁,不阻塞
std::unique_lock<std::mutex> lock3(mtx, std::try_to_lock);
// 4. 接管已加锁的互斥量
mtx.lock();
std::unique_lock<std::mutex> lock4(mtx, std::adopt_lock);
std::defer_lock 是一个空标签类型,用于指示 unique_lock 在构造时不立即加锁。这在需要同时获取多个锁时非常有用,可以避免死锁。
#include <mutex>
#include <thread>
std::mutex mtx1, mtx2;
void process_data() {
// 使用defer_lock构造,但不立即加锁
std::unique_lock<std::mutex> lock1(mtx1, std::defer_lock);
std::unique_lock<std::mutex> lock2(mtx2, std::defer_lock);
// 同时锁定两个锁,避免死锁
std::lock(lock1, lock2);
// 临界区操作
std::cout << "Processing data with both locks\n";
// 析构时自动解锁
}
完整示例:
void advanced_lock_example() {
std::mutex mtx;
{
// 延迟加锁
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
// 手动加锁
lock.lock();
std::cout << "Critical section\n";
// 手动解锁(可选)
lock.unlock();
// 可以重新加锁
lock.lock();
std::cout << "Re-entered critical section\n";
// 检查是否持有锁
if (lock.owns_lock()) {
std::cout << "Lock is owned\n";
}
// 析构时如果持有锁会自动解锁
}
}
3.3 多锁管理:std::lock与std::try_lock
std::lock 可以同时锁定多个互斥量,避免死锁。std::try_lock 尝试同时锁定多个互斥量。
#include <mutex>
#include <thread>
std::mutex mtx_a, mtx_b;
void task_1() {
// 安全的方式:同时锁定两个互斥量
std::lock(mtx_a, mtx_b);
// 使用adopt_lock接管已锁定的互斥量
std::lock_guard<std::mutex> lock_a(mtx_a, std::adopt_lock);
std::lock_guard<std::mutex> lock_b(mtx_b, std::adopt_lock);
std::cout << "Task 1 executing\n";
}
void task_2() {
// 尝试同时锁定
int result = std::try_lock(mtx_a, mtx_b);
if (result == -1) {
// 成功锁定所有互斥量
std::lock_guard<std::mutex> lock_a(mtx_a, std::adopt_lock);
std::lock_guard<std::mutex> lock_b(mtx_b, std::adopt_lock);
std::cout << "Task 2 acquired all locks\n";
} else {
std::cout << "Task 2 failed to acquire lock " << result << "\n";
}
}
四、条件变量:线程间同步
4.1 condition_variable的基本使用
std::condition_variable 用于线程间的同步,必须与 std::unique_lock 配合使用。
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;
bool finished = false;
void producer() {
for (int i = 0; i < 10; ++i) {
std::lock_guard<std::mutex> lock(mtx);
data_queue.push(i);
std::cout << "Produced: " << i << std::endl;
cv.notify_one(); // 通知一个消费者
}
{
std::lock_guard<std::mutex> lock(mtx);
finished = true;
}
cv.notify_all(); // 通知所有消费者
}
void consumer() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
// 等待条件满足:有数据或生产结束
cv.wait(lock, []() {
return !data_queue.empty() || finished;
});
if (finished && data_queue.empty()) {
break;
}
int data = data_queue.front();
data_queue.pop();
lock.unlock(); // 尽早释放锁
std::cout << "Consumed: " << data << std::endl;
}
}
4.2 经典案例:交替打印奇偶数
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool is_even_turn = true; // 控制打印顺序
void print_numbers(int start, int max, bool is_even) {
for (int i = start; i <= max; i += 2) {
std::unique_lock<std::mutex> lock(mtx);
// 等待轮到当前线程打印
cv.wait(lock, [is_even]() {
return is_even_turn == is_even;
});
std::cout << (is_even ? "Even: " : "Odd: ") << i << std::endl;
// 切换打印权
is_even_turn = !is_even_turn;
// 通知另一个线程
cv.notify_one();
}
}
int main() {
std::thread t1(print_numbers, 0, 10, true); // 打印偶数
std::thread t2(print_numbers, 1, 10, false); // 打印奇数
t1.join();
t2.join();
return 0;
}
五、原子操作:无锁编程
5.1 std::atomic基础类型
std::atomic 提供线程安全的原子操作,无需显式加锁。
#include <atomic>
#include <thread>
#include <vector>
#include <iostream>
std::atomic<int> atomic_counter{0};
int normal_counter = 0;
void atomic_increment(int n) {
for (int i = 0; i < n; ++i) {
atomic_counter.fetch_add(1, std::memory_order_relaxed);
}
}
void normal_increment(int n) {
for (int i = 0; i < n; ++i) {
++normal_counter; // 存在数据竞争
}
}
int main() {
std::vector<std::thread> threads;
// 测试原子计数器
for (int i = 0; i < 4; ++i) {
threads.emplace_back(atomic_increment, 100000);
}
for (auto& t : threads) {
t.join();
}
threads.clear();
std::cout << "Atomic counter: " << atomic_counter << std::endl; // 总是400000
// 测试普通计数器(结果不确定)
for (int i = 0; i < 4; ++i) {
threads.emplace_back(normal_increment, 100000);
}
for (auto& t : threads) {
t.join();
}
std::cout << "Normal counter: " << normal_counter << std::endl; // 可能小于400000
return 0;
}
5.2 CAS操作详解
CAS(Compare-And-Swap)是原子操作的核心机制,它比较并交换内存值,是现代无锁编程的基础。
CAS基本语义:
bool compare_exchange_weak(T& expected, T desired);
bool compare_exchange_strong(T& expected, T desired);
工作原理:
- 如果原子变量的值等于
expected,则用desired更新原子变量,返回true - 如果原子变量的值不等于
expected,则将原子变量的当前值写入expected,返回false
weak vs strong:
compare_exchange_weak:可能虚假失败(spurious failure),但性能更好compare_exchange_strong:保证不会虚假失败,性能稍差
#include <atomic>
#include <iostream>
void cas_example() {
std::atomic<int> value{10};
int expected = 10;
// 使用CAS实现原子更新
while (!value.compare_exchange_weak(expected, 20)) {
// 如果value不等于expected,expected会被更新为value的当前值
std::cout << "CAS failed, expected was: " << expected << std::endl;
// 可以在这里根据expected的值决定新的desired值
}
std::cout << "CAS succeeded, value is now: " << value << std::endl;
}
// 使用CAS实现无锁栈的push操作
template<typename T>
class LockFreeStack {
private:
struct Node {
T data;
Node* next;
Node(const T& data) : data(data), next(nullptr) {}
};
std::atomic<Node*> head{nullptr};
public:
void push(const T& data) {
Node* new_node = new Node(data);
new_node->next = head.load(std::memory_order_relaxed);
// CAS循环:确保原子性更新head
while (!head.compare_exchange_weak(new_node->next, new_node,
std::memory_order_release,
std::memory_order_relaxed)) {
// 循环直到成功,如果失败,new_node->next会被更新为当前的head
}
}
};
CAS在链表操作中的应用:
#include <atomic>
// 简单的全局链表
struct Node {
int value;
Node* next;
};
std::atomic<Node*> list_head(nullptr);
void append(int val) {
Node* new_node = new Node{val, nullptr};
// 无锁地添加到链表头部
Node* old_head = list_head.load();
do {
new_node->next = old_head;
} while (!list_head.compare_exchange_weak(old_head, new_node));
// 等价于:list_head = new_node,但是线程安全的
}
5.3 内存顺序模型详解
C++11 提供了6种内存顺序,在性能和一致性之间提供不同级别的保证。
| 内存顺序 | 适用操作 | 语义描述 |
|---|---|---|
memory_order_relaxed |
任意操作 | 仅保证原子性,无同步约束 |
memory_order_consume |
加载操作 | 保证依赖链的可见性 |
memory_order_acquire |
加载操作 | 保证后续操作不会重排到前面 |
memory_order_release |
存储操作 | 保证前面操作不会重排到后面 |
memory_order_acq_rel |
读-改-写 | 同时具有acquire和release语义 |
memory_order_seq_cst |
任意操作 | 全局顺序一致性(默认) |
示例:发布-消费模式
#include <atomic>
#include <thread>
#include <cassert>
std::atomic<int*> data_ptr{nullptr};
std::atomic<int> data_ready{0};
void producer() {
int* p = new int(42);
// 发布数据
data_ptr.store(p, std::memory_order_release);
data_ready.store(1, std::memory_order_release);
}
void consumer() {
// 等待数据就绪
while (data_ready.load(std::memory_order_acquire) == 0) {
// 忙等待
}
// 获取数据
int* p = data_ptr.load(std::memory_order_acquire);
assert(*p == 42); // 总是成立
delete p;
}
5.4 原子标志与自旋锁实现
std::atomic_flag 是最简单的原子类型,保证无锁。
#include <atomic>
#include <thread>
// 基于atomic_flag的自旋锁
class SpinLock {
private:
std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:
void lock() {
// 测试并设置,如果原值为false则设置为true并返回false
while (flag.test_and_set(std::memory_order_acquire)) {
// 忙等待,可以插入pause指令减少CPU占用
#ifdef __x86_64__
__builtin_ia32_pause();
#endif
}
}
void unlock() {
flag.clear(std::memory_order_release);
}
bool try_lock() {
return !flag.test_and_set(std::memory_order_acquire);
}
};
// 测试自旋锁
SpinLock spin_lock;
int shared_value = 0;
void spinlock_test(int n) {
for (int i = 0; i < n; ++i) {
spin_lock.lock();
++shared_value;
spin_lock.unlock();
}
}
六、异步编程工具
6.1 std::future与std::promise
std::future 和 std::promise 提供了一种线程间传递结果的机制,允许一个线程等待另一个线程的结果。
基本用法:
#include <iostream>
#include <thread>
#include <future>
#include <chrono>
void basic_future_promise() {
// 创建promise和future对
std::promise<int> prom;
std::future<int> fut = prom.get_future();
// 在另一个线程中设置值
std::thread worker([&prom]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
prom.set_value(42); // 设置结果值
// prom.set_exception(std::make_exception_ptr(std::runtime_error("Error")));
});
// 在主线程中获取结果
std::cout << "Waiting for result..." << std::endl;
int result = fut.get(); // 阻塞直到结果可用
std::cout << "Result: " << result << std::endl;
worker.join();
}
异常传递:
void future_with_exception() {
std::promise<void> prom;
std::future<void> fut = prom.get_future();
std::thread worker([&prom]() {
try {
// 模拟可能抛出异常的操作
throw std::runtime_error("Something went wrong!");
prom.set_value(); // 正常完成
} catch (...) {
prom.set_exception(std::current_exception()); // 传递异常
}
});
try {
fut.get(); // 如果worker抛出异常,这里会重新抛出
std::cout << "Success!" << std::endl;
} catch (const std::exception& e) {
std::cout << "Caught exception: " << e.what() << std::endl;
}
worker.join();
}
6.2 std::shared_future
std::shared_future 允许多个线程等待同一个结果,可以被多次调用 get()。
#include <future>
#include <thread>
#include <vector>
void shared_future_example() {
std::promise<int> prom;
std::shared_future<int> shared_fut = prom.get_future(); // 可以隐式转换
// 多个消费者线程
std::vector<std::thread> consumers;
for (int i = 0; i < 3; ++i) {
consumers.emplace_back([shared_fut, i]() {
// 每个线程都可以调用get()
int result = shared_fut.get();
std::cout << "Consumer " << i << " got: " << result << std::endl;
});
}
// 生产者线程
std::thread producer([&prom]() {
std::this_thread::sleep_for(std::chrono::seconds(1));
prom.set_value(100);
});
producer.join();
for (auto& t : consumers) {
t.join();
}
}
6.3 std::async与启动策略
std::async 是启动异步任务的便捷方式,支持不同的启动策略。
启动策略:
std::launch::async:在新线程中执行任务std::launch::deferred:延迟执行,直到调用get()时执行std::launch::async | std::launch::deferred:由实现选择(默认)
#include <future>
#include <iostream>
#include <chrono>
int compute(int x, int y) {
std::this_thread::sleep_for(std::chrono::seconds(1));
return x + y;
}
void async_example() {
// 异步执行(新线程)
auto fut1 = std::async(std::launch::async, compute, 10, 20);
// 延迟执行(当前线程)
auto fut2 = std::async(std::launch::deferred, compute, 30, 40);
std::cout << "Async task started..." << std::endl;
// fut1.get()会阻塞直到异步任务完成
std::cout << "Async result: " << fut1.get() << std::endl;
// fut2.get()会立即在当前线程执行compute函数
std::cout << "Deferred result: " << fut2.get() << std::endl;
}
// 使用async进行并行计算
void parallel_computation() {
auto start = std::chrono::high_resolution_clock::now();
// 启动多个异步任务
auto fut1 = std::async(std::launch::async, []() {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return 1;
});
auto fut2 = std::async(std::launch::async, []() {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return 2;
});
auto fut3 = std::async(std::launch::async, []() {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return 3;
});
// 并行执行,总时间约500ms而不是1500ms
int result = fut1.get() + fut2.get() + fut3.get();
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Result: " << result << ", Time: " << duration.count() << "ms" << std::endl;
}
6.4 std::packaged_task
std::packaged_task 将可调用对象包装成可以产生future的任务。
#include <future>
#include <iostream>
#include <queue>
#include <thread>
void packaged_task_example() {
// 包装一个函数
std::packaged_task<int(int, int)> task([](int a, int b) {
return a * b;
});
// 获取future
std::future<int> fut = task.get_future();
// 在另一个线程中执行任务
std::thread worker(std::move(task), 6, 7);
// 获取结果
std::cout << "6 * 7 = " << fut.get() << std::endl;
worker.join();
}
// 任务队列示例
void task_queue_example() {
std::queue<std::packaged_task<int()>> tasks;
std::mutex queue_mutex;
std::condition_variable queue_cv;
bool stop = false;
// 工作线程
std::thread worker([&]() {
while (true) {
std::packaged_task<int()> task;
{
std::unique_lock<std::mutex> lock(queue_mutex);
queue_cv.wait(lock, [&]() { return stop || !tasks.empty(); });
if (stop && tasks.empty()) break;
task = std::move(tasks.front());
tasks.pop();
}
task(); // 执行任务
}
});
// 提交任务
std::vector<std::future<int>> results;
for (int i = 0; i < 5; ++i) {
std::packaged_task<int()> task([i]() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return i * i;
});
results.push_back(task.get_future());
{
std::lock_guard<std::mutex> lock(queue_mutex);
tasks.push(std::move(task));
}
queue_cv.notify_one();
}
// 停止工作线程
{
std::lock_guard<std::mutex> lock(queue_mutex);
stop = true;
}
queue_cv.notify_one();
worker.join();
// 获取结果
for (auto& fut : results) {
std::cout << "Result: " << fut.get() << std::endl;
}
}
6.5 std::future_status
std::future_status 用于检查future的状态,避免阻塞等待。
#include <future>
#include <iostream>
#include <chrono>
void future_status_example() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
// 启动一个延迟的任务
std::thread worker([&prom]() {
std::this_thread::sleep_for(std::chrono::seconds(2));
prom.set_value(42);
});
// 非阻塞地检查状态
while (true) {
auto status = fut.wait_for(std::chrono::milliseconds(500));
if (status == std::future_status::ready) {
std::cout << "Task completed! Result: " << fut.get() << std::endl;
break;
} else if (status == std::future_status::timeout) {
std::cout << "Still waiting..." << std::endl;
} else if (status == std::future_status::deferred) {
std::cout << "Task is deferred" << std::endl;
break;
}
}
worker.join();
}
// 带超时的等待
void future_with_timeout() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
std::thread worker([&prom]() {
std::this_thread::sleep_for(std::chrono::seconds(5)); // 长时间任务
prom.set_value(100);
});
// 最多等待2秒
auto status = fut.wait_for(std::chrono::seconds(2));
if (status == std::future_status::ready) {
std::cout << "Got result: " << fut.get() << std::endl;
} else if (status == std::future_status::timeout) {
std::cout << "Timeout! Task is still running." << std::endl;
// 可以取消任务或采取其他措施
}
worker.detach(); // 由于超时,让worker在后台运行
}
七、高级并发工具
7.1 std::call_once:一次性执行
std::call_once 保证某个函数在多线程环境中只执行一次。
#include <mutex>
#include <thread>
#include <vector>
std::once_flag init_flag;
void initialize() {
std::cout << "Initialization called only once!\n";
}
void worker() {
std::call_once(init_flag, initialize);
std::cout << "Worker running\n";
}
int main() {
std::vector<std::thread> threads;
for (int i = 0; i < 5; ++i) {
threads.emplace_back(worker);
}
for (auto& t : threads) {
t.join();
}
return 0;
}
7.2 无锁数据结构示例
使用原子操作和CAS实现无锁栈:
#include <atomic>
#include <memory>
template<typename T>
class LockFreeStack {
private:
struct Node {
T data;
Node* next;
Node(const T& data) : data(data), next(nullptr) {}
};
std::atomic<Node*> head{nullptr};
public:
void push(const T& data) {
Node* new_node = new Node(data);
new_node->next = head.load(std::memory_order_relaxed);
// CAS循环:确保原子性更新head
while (!head.compare_exchange_weak(new_node->next, new_node,
std::memory_order_release,
std::memory_order_relaxed)) {
// 循环直到成功
}
}
bool pop(T& result) {
Node* old_head = head.load(std::memory_order_relaxed);
while (old_head &&
!head.compare_exchange_weak(old_head, old_head->next,
std::memory_order_acquire,
std::memory_order_relaxed)) {
// 循环直到成功或栈为空
}
if (!old_head) {
return false; // 栈为空
}
result = old_head->data;
delete old_head;
return true;
}
// 使用shared_ptr避免pop时的内存管理问题
std::shared_ptr<T> pop() {
Node* old_head = head.load(std::memory_order_relaxed);
while (old_head &&
!head.compare_exchange_weak(old_head, old_head->next,
std::memory_order_acquire,
std::memory_order_relaxed)) {
}
if (!old_head) {
return std::shared_ptr<T>();
}
std::shared_ptr<T> res(std::make_shared<T>(old_head->data));
delete old_head;
return res;
}
};
八、总结
核心技术要点
-
线程管理:
- 使用
std::thread创建跨平台线程 - 注意参数传递时使用
std::ref进行引用传递 - 使用
std::this_thread管理当前线程
- 使用
-
同步机制:
- 互斥锁:
std::mutex、std::timed_mutex、std::recursive_mutex - RAII锁管理:优先使用
std::lock_guard和std::unique_lock - 条件变量:
std::condition_variable用于线程间通信
- 互斥锁:
-
原子操作与CAS:
std::atomic提供无锁的线程安全操作- CAS是实现无锁数据结构的核心机制
- 理解不同内存顺序的性能和一致性权衡
std::atomic_flag用于实现自旋锁等底层同步
-
异步编程:
std::future/std::promise:线程间结果传递std::shared_future:多线程共享结果std::async:便捷的异步任务启动std::packaged_task:包装可调用对象为任务std::future_status:非阻塞状态检查
-
高级工具:
std::call_once保证一次性初始化- 无锁数据结构适用于高并发场景
实践建议
-
资源管理:
- 优先使用 RAII 类型管理锁资源
- 使用
std::lock同时获取多个锁避免死锁
-
性能考虑:
- 根据场景选择合适的同步机制
- 短临界区使用自旋锁,长临界区使用互斥锁
- 计数器等简单操作使用原子变量
- 高并发场景考虑无锁数据结构
-
异步编程:
- 使用
std::async简化异步任务创建 - 合理选择启动策略(async/deferred)
- 使用
future_status实现非阻塞等待
- 使用
-
CAS使用技巧:
- 在循环中使用
compare_exchange_weak - 根据expected的值决定新的desired值
- 注意内存顺序的选择
- 在循环中使用
-
代码安全:
- 避免在持有锁时执行耗时操作
- 使用条件变量时注意虚假唤醒
- 确保异常安全,利用 RAII 自动释放资源
更多推荐



所有评论(0)