当前位置: 首页 > backend >正文

C++多线程编程:std::thread, std::async, std::future

1. C++多线程基础

传统的多线程问题

// 传统C++需要平台特定的API
#ifdef _WIN32#include <windows.h>HANDLE thread = CreateThread(...);
#else#include <pthread.h>pthread_t thread;pthread_create(&thread, ...);
#endif
// 代码不可移植,难以维护

C++11标准线程库

#include <thread>
#include <iostream>// 跨平台的多线程编程!
void thread_function() {std::cout << "Hello from thread! Thread ID: " << std::this_thread::get_id() << std::endl;
}int main() {std::thread t(thread_function); // 创建线程std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;t.join(); // 等待线程结束return 0;
}

2. std::thread 详解

创建线程的多种方式

#include <thread>
#include <iostream>// 1. 函数指针
void simple_function() {std::cout << "Simple function thread" << std::endl;
}// 2. Lambda表达式
auto lambda = [] {std::cout << "Lambda thread" << std::endl;
};// 3. 函数对象(仿函数)
struct Functor {void operator()() {std::cout << "Functor thread" << std::endl;}
};// 4. 成员函数
class Worker {
public:void work() {std::cout << "Member function thread" << std::endl;}
};int main() {// 创建线程的多种方式std::thread t1(simple_function);std::thread t2(lambda);std::thread t3(Functor());Worker worker;std::thread t4(&Worker::work, &worker); // 成员函数需要对象指针// 带参数的线程函数std::thread t5([](int x, const std::string& s) {std::cout << "Params: " << x << ", " << s << std::endl;}, 42, "hello");t1.join(); t2.join(); t3.join(); t4.join(); t5.join();
}

线程管理和生命周期

void worker(int id) {std::cout << "Worker " << id << " started" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "Worker " << id << " finished" << std::endl;
}int main() {std::thread t1(worker, 1);std::thread t2(worker, 2);// 检查线程是否可joinif (t1.joinable()) {std::cout << "t1 is joinable" << std::endl;}// 分离线程(守护线程)t2.detach();// 等待t1结束t1.join();// t2已经被detach,不需要join// 注意:detach后线程独立运行,主线程结束可能终止子线程return 0;
}

线程转移所有权

void task() {std::this_thread::sleep_for(std::chrono::seconds(1));
}int main() {// 线程对象只能移动,不能拷贝std::thread t1(task);// 错误:线程对象不能拷贝// std::thread t2 = t1;// 正确:移动语义std::thread t2 = std::move(t1);// 现在t1不再关联任何线程if (!t1.joinable()) {std::cout << "t1 is not joinable" << std::endl;}t2.join();// 在容器中存储线程std::vector<std::thread> threads;for (int i = 0; i < 5; ++i) {threads.emplace_back([](int id) {std::cout << "Thread " << id << std::endl;}, i);}// 等待所有线程完成for (auto& t : threads) {t.join();}return 0;
}

3. std::async 和 std::future

异步任务执行

#include <future>
#include <iostream>
#include <chrono>int long_running_task(int x) {std::this_thread::sleep_for(std::chrono::seconds(2));return x * x;
}int main() {// 启动异步任务std::future<int> result = std::async(std::launch::async, long_running_task, 5);std::cout << "Main thread can do other work..." << std::endl;// 获取结果(如果还没完成会阻塞等待)int value = result.get();std::cout << "Result: " << value << std::endl;return 0;
}

std::async 的启动策略

int compute(int x) {return x * x;
}int main() {// 1. 异步执行(在新线程中)auto future1 = std::async(std::launch::async, compute, 5);// 2. 延迟执行(在get()/wait()时执行)auto future2 = std::async(std::launch::deferred, compute, 10);// 3. 自动选择(由实现决定)auto future3 = std::async(std::launch::async | std::launch::deferred, compute, 15);std::cout << "Future1 result: " << future1.get() << std::endl;std::cout << "Future2 result: " << future2.get() << std::endl; // 此时才执行std::cout << "Future3 result: " << future3.get() << std::endl;return 0;
}

std::future 的方法

int task() {std::this_thread::sleep_for(std::chrono::seconds(1));return 42;
}int main() {std::future<int> fut = std::async(task);// 检查状态if (fut.valid()) {std::cout << "Future is valid" << std::endl;}// 等待结果(阻塞)// fut.wait();// 带超时的等待auto status = fut.wait_for(std::chrono::milliseconds(500));if (status == std::future_status::ready) {std::cout << "Task completed: " << fut.get() << std::endl;} else if (status == std::future_status::timeout) {std::cout << "Task still running..." << std::endl;std::cout << "Final result: " << fut.get() << std::endl; // 继续等待}return 0;
}

4. std::promise 和 std::packaged_task

std::promise:显式设置值

void producer(std::promise<int> 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")));
}int main() {std::promise<int> prom;std::future<int> fut = prom.get_future();std::thread t(producer, std::move(prom));// 消费者等待结果try {int result = fut.get();std::cout << "Received: " << result << std::endl;} catch (const std::exception& e) {std::cout << "Exception: " << e.what() << std::endl;}t.join();return 0;
}

std::packaged_task:包装可调用对象

int complex_computation(int x, int y) {std::this_thread::sleep_for(std::chrono::seconds(1));return x * x + y * y;
}int main() {// 包装函数std::packaged_task<int(int, int)> task(complex_computation);std::future<int> result = task.get_future();// 在单独线程中执行std::thread t(std::move(task), 3, 4);// 获取结果std::cout << "Result: " << result.get() << std::endl;t.join();// 也可以在当前线程执行std::packaged_task<int(int, int)> task2(complex_computation);std::future<int> result2 = task2.get_future();task2(5, 6); // 同步执行std::cout << "Result2: " << result2.get() << std::endl;return 0;
}

5. 线程同步和互斥

基本的互斥锁

#include <mutex>
#include <thread>
#include <vector>std::mutex g_mutex;
int shared_data = 0;void increment() {for (int i = 0; i < 100000; ++i) {std::lock_guard<std::mutex> lock(g_mutex); // RAII锁++shared_data;}
}int main() {std::vector<std::thread> threads;for (int i = 0; i < 10; ++i) {threads.emplace_back(increment);}for (auto& t : threads) {t.join();}std::cout << "Final value: " << shared_data << std::endl;return 0;
}

各种互斥锁类型

#include <mutex>
#include <shared_mutex>std::mutex mtx; // 基本互斥锁
std::recursive_mutex rec_mtx; // 递归互斥锁
std::timed_mutex timed_mtx; // 带超时的互斥锁
std::shared_mutex shared_mtx; // 读写锁(C++17)void reader() {// 写法1:显式模板参数(兼容性更好)std::shared_lock<std::shared_mutex> lock(shared_mtx);// 多个读取者可以同时访问// 写法2:C++17 CTAD(需要编译器支持)// std::shared_lock lock(shared_mtx);
}void writer() {// 写法1:显式模板参数(兼容性更好)std::unique_lock<std::shared_mutex> lock(shared_mtx);// 只有一个写入者可以访问// 写法2:C++17 CTAD(需要编译器支持)// std::unique_lock lock(shared_mtx);
}

6. 实际应用场景

并行计算

#include <vector>
#include <numeric>
#include <future>// 并行累加
template<typename Iterator>
typename Iterator::value_type parallel_sum(Iterator begin, Iterator end) {auto size = std::distance(begin, end);if (size < 1000) {return std::accumulate(begin, end, 0);}Iterator mid = begin;std::advance(mid, size / 2);auto left = std::async(std::launch::async, parallel_sum<Iterator>, begin, mid);auto right = parallel_sum(mid, end); // 当前线程执行return left.get() + right;
}int main() {std::vector<int> data(10000, 1); // 10000个1auto start = std::chrono::high_resolution_clock::now();int sum = parallel_sum(data.begin(), data.end());auto end = std::chrono::high_resolution_clock::now();std::cout << "Sum: " << sum << std::endl;std::cout << "Time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()<< "ms" << std::endl;return 0;
}

生产者-消费者模式

#include <queue>
#include <condition_variable>template<typename T>
class ThreadSafeQueue {
private:std::queue<T> queue;mutable std::mutex mtx;std::condition_variable cv;public:void push(T value) {std::lock_guard lock(mtx);queue.push(std::move(value));cv.notify_one();}T pop() {std::unique_lock lock(mtx);cv.wait(lock, [this] { return !queue.empty(); });T value = std::move(queue.front());queue.pop();return value;}
};void producer(ThreadSafeQueue<int>& queue) {for (int i = 0; i < 10; ++i) {queue.push(i);std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}void consumer(ThreadSafeQueue<int>& queue, int id) {for (int i = 0; i < 5; ++i) {int value = queue.pop();std::cout << "Consumer " << id << " got: " << value << std::endl;}
}

7. 常见问题

Q1: std::thread 和 std::async 的区别?

  • std::thread:直接管理线程,需要手动join/detach

  • std::async:高级抽象,返回future自动管理,可以选择异步或延迟执行

Q2: 什么是std::future?

std::future是一个异步操作结果的占位符,提供获取结果、等待完成、查询状态的方法。

Q3: std::promise 和 std::packaged_task 的区别?

  • std::promise:手动设置值或异常

  • std::packaged_task:包装可调用对象,自动设置返回值

Q4: 如何避免数据竞争?

:使用互斥锁(std::mutex)、原子操作(std::atomic)、线程安全的数据结构,遵循RAII原则使用std::lock_guard等。

Q5: 什么是死锁?如何避免?

:多个线程互相等待对方释放锁。避免方法:按固定顺序获取锁、使用std::lock()同时获取多个锁、使用超时锁、避免嵌套锁。

8. 最佳实践

使用RAII管理线程

class ThreadGuard {
public:explicit ThreadGuard(std::thread t) : t_(std::move(t)) {}~ThreadGuard() {if (t_.joinable()) {t_.join();}}// 禁止拷贝ThreadGuard(const ThreadGuard&) = delete;ThreadGuard& operator=(const ThreadGuard&) = delete;private:std::thread t_;
};void safe_thread_usage() {ThreadGuard guard(std::thread([]{std::this_thread::sleep_for(std::chrono::seconds(1));}));// 线程自动在guard析构时join
}

异常安全的多线程代码

void process_data() {std::promise<int> prom;auto fut = prom.get_future();std::thread t([&prom] {try {// 可能抛出异常的操作int result = risky_operation();prom.set_value(result);} catch (...) {prom.set_exception(std::current_exception());}});try {int result = fut.get();// 处理结果} catch (const std::exception& e) {std::cerr << "Thread failed: " << e.what() << std::endl;}t.join();
}

总结

C++11多线程编程提供了现代、安全的并发工具:

  • ✅ std::thread:直接线程管理

  • ✅ std::async/std::future:异步任务和结果处理

  • ✅ std::promise/packaged_task:更灵活的异步编程

  • ✅ RAII支持:自动资源管理

  • ✅ 类型安全:编译期检查

http://www.xdnf.cn/news/19612.html

相关文章:

  • Jenkins Pipeline 语法
  • 第 12 篇:网格边界安全 - Egress Gateway 与最佳实践
  • python中的zip() 函数介绍及使用说明
  • 基于Spark的新冠肺炎疫情实时监控系统_django+spider
  • HTML第三课:特殊元素
  • 跨境电商账号风控核心:IP纯净度与浏览器指纹的防护策略
  • 跳出“中央集权”的泥潭:以Data Mesh重构AI时代的活性数据治理
  • MySQL8.0 新特性随笔
  • css中 ,有哪些⽅式可以隐藏页⾯元素? 区别?
  • 详细介绍RIGHT JOIN及其用法
  • Vue2 入门(一)介绍及Demo项目创建
  • 【51单片机6位数码管显示矩阵键值至右向左自左向右】2022-11-29
  • Linux驱动开发学习笔记
  • web自动化测试(selenium)
  • [架构之美]pdf压缩实战笔记(十五)
  • FlutterUnit 3.3.0 | 全组件、全属性、鸿蒙支持来袭
  • 高德开放平台智能眼镜解决方案,Rokid Glasses AR导航实测
  • Proxy 我踩过的那些坑
  • apache-jmeter-5.1.1安装部署与使用教程(小白一看就会)​
  • 【游戏开发】街景风格化运用到游戏中,一般有哪些风格可供选择?
  • 【实测】安装最新Unity6的常规操作
  • intellij idea2021.3.3版本如何获取永久权限
  • 第二章:技术基石:写出“活”的代码(1)
  • 基础算法之二分算法 --- 1
  • AI-调查研究-67-具身智能 核心技术构成全解析:感知、决策、学习与交互的闭环系统
  • DVWA靶场通关笔记-DOM型XSS(Impossible级别)
  • 服务器托管需要注意什么事项?
  • STM32CUBEMX配置LAN8720a实现UDP通信
  • pycharm无法添加本地conda解释器/命令行激活conda时出现很多无关内容
  • 阿里云国际代理商:如何重置阿里云服务器密码?