目录

一、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_mutexstd::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_locklock_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::futurestd::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;
    }
};

八、总结

核心技术要点

  1. 线程管理

    • 使用 std::thread 创建跨平台线程
    • 注意参数传递时使用 std::ref 进行引用传递
    • 使用 std::this_thread 管理当前线程
  2. 同步机制

    • 互斥锁:std::mutexstd::timed_mutexstd::recursive_mutex
    • RAII锁管理:优先使用 std::lock_guardstd::unique_lock
    • 条件变量:std::condition_variable 用于线程间通信
  3. 原子操作与CAS

    • std::atomic 提供无锁的线程安全操作
    • CAS是实现无锁数据结构的核心机制
    • 理解不同内存顺序的性能和一致性权衡
    • std::atomic_flag 用于实现自旋锁等底层同步
  4. 异步编程

    • std::future/std::promise:线程间结果传递
    • std::shared_future:多线程共享结果
    • std::async:便捷的异步任务启动
    • std::packaged_task:包装可调用对象为任务
    • std::future_status:非阻塞状态检查
  5. 高级工具

    • std::call_once 保证一次性初始化
    • 无锁数据结构适用于高并发场景

实践建议

  1. 资源管理

    • 优先使用 RAII 类型管理锁资源
    • 使用 std::lock 同时获取多个锁避免死锁
  2. 性能考虑

    • 根据场景选择合适的同步机制
    • 短临界区使用自旋锁,长临界区使用互斥锁
    • 计数器等简单操作使用原子变量
    • 高并发场景考虑无锁数据结构
  3. 异步编程

    • 使用 std::async 简化异步任务创建
    • 合理选择启动策略(async/deferred)
    • 使用 future_status 实现非阻塞等待
  4. CAS使用技巧

    • 在循环中使用 compare_exchange_weak
    • 根据expected的值决定新的desired值
    • 注意内存顺序的选择
  5. 代码安全

    • 避免在持有锁时执行耗时操作
    • 使用条件变量时注意虚假唤醒
    • 确保异常安全,利用 RAII 自动释放资源
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐