cpp多线程学习
1.thread
std::thread
是 C++11 引入的跨平台线程管理类,封装了操作系统的线程 API(如 pthread、Windows 线程),提供统一的线程操作接口。线程的生命周期由join()
和detach()
控制。
thread在创建时就开始执行
join():阻塞当前线程,等待目标线程执行完毕。执行后线程资源释放,不可再次join
。
detach():分离线程(后台运行),无需等待。线程结束后自动释放资源(无法再join
)。
2.mutex
直接调用lock()
/unlock()
易导致死锁(如临界区抛出异常未解锁)。C++ 提供 RAII(资源获取即初始化)包装类自动管理锁的生命周期:
std::lock_guard:构造时加锁,析构时解锁(不可手动解锁)。
std::unique_lock:构造时可选延迟加锁(std::defer_lock
),支持手动解锁、转移锁所有权。
3.condition_variable
std::condition_variable
是线程间通信的工具,允许一个或多个线程等待某个条件满足(由其他线程通知唤醒),避免无效的轮询等待。
与unique_lock结合使用
wait(lock):阻塞当前线程,直到被notify_one()
/notify_all()
唤醒(自动释放锁)。
wait(lock, predicate):带谓词的等待:仅当predicate()
返回true
时唤醒(避免虚假唤醒)。谓词(predicate
)的作用是在被notify唤醒后检查条件是否满足,其内部等价于下述代码
while (!predicate()) {wait(lock); // 释放锁并阻塞,直到被唤醒
}
notify_one()、notify_all():唤醒线程
4.atomic
std::atomic<T>
是模板类,用于定义原子类型,确保对其的操作是原子的(不可分割),避免多线程访问时的数据竞争。适用于int等简单基本类型
以有界缓冲区为例
#include <queue>
#include <mutex>
#include <condition_variable>template<typename T>
class BoundedBuffer {
public:explicit BoundedBuffer(size_t capacity) : capacity_(capacity) {if (capacity == 0) {throw std::invalid_argument("Buffer capacity must be greater than 0");}}// 入队操作(阻塞直到有空间)void push(T element) {std::unique_lock<std::mutex> lock(mtx_);// 等待缓冲区不满(处理虚假唤醒)not_full_.wait(lock, [this] { return queue_.size() < capacity_; });queue_.push(std::move(element)); // 使用移动语义避免拷贝not_empty_.notify_one(); // 通知可能等待的出队操作}// 出队操作(阻塞直到有元素)T pop() {std::unique_lock<std::mutex> lock(mtx_);// 等待缓冲区非空(处理虚假唤醒)not_empty_.wait(lock, [this] { return !queue_.empty(); });auto val = std::move(queue_.front()); // 使用移动语义避免拷贝queue_.pop();not_full_.notify_one(); // 通知可能等待的入队操作return val;}// 获取当前元素数量(线程安全)size_t size() const {std::lock_guard<std::mutex> lock(mtx_);return queue_.size();}private:std::queue<T> queue_;mutable std::mutex mtx_; // mutable允许在const成员函数中加锁std::condition_variable not_full_; // 缓冲区不满条件变量std::condition_variable not_empty_; // 缓冲区非空条件变量const size_t capacity_; // 缓冲区最大容量
};int main() {const size_t buffer_capacity = 5;const int data_count = 10; // 每个生产者生产10个数据BoundedBuffer<int> buffer(buffer_capacity);// 生产者线程:向缓冲区推送数据auto producer = [&buffer, data_count](int producer_id) {for (int i = 0; i < data_count; ++i) {buffer.push(producer_id * 100 + i); // 生产数据(ID+序号)std::this_thread::sleep_for(std::chrono::milliseconds(50)); // 模拟生产耗时}};// 消费者线程:从缓冲区取出数据auto consumer = [&buffer, data_count](int consumer_id) {for (int i = 0; i < data_count; ++i) {int val = buffer.pop(); // 消费数据(阻塞直到有数据)std::cout << "Consumer " << consumer_id << " popped: " << val << std::endl;}};// 创建线程std::vector<std::thread> threads;threads.emplace_back(producer, 1); // 生产者1threads.emplace_back(producer, 2); // 生产者2threads.emplace_back(consumer, 1); // 消费者1threads.emplace_back(consumer, 2); // 消费者2// 主线程等待所有线程完成(join)for (auto& t : threads) {if (t.joinable()) { // 避免重复join(如线程已detach)t.join(); // 阻塞主线程,直到所有生产者/消费者完成}}std::cout << "All threads completed." << std::endl;return 0;
}