C++多线程中如何用std::shared_ptr等实现get函数结果复用?
完全可以用这些工具实现你的需求,核心思路是用原子化的std::shared_ptr包裹std::future,确保只有第一个任务触发耗时的get()函数调用,后续所有任务共享同一个future的结果——要么直接读取已就绪的数据,要么阻塞等待数据准备完成。
设计核心要点
- 替换全局变量:把原全局
Objs.text替换为一个原子共享指针:std::atomic<std::shared_ptr<std::future<数据类型>>> g_future_ptr;(数据类型根据get()返回值调整,示例中用std::string)。 - 任务逻辑:每个任务的
check()方法中:- 原子加载当前的
g_future_ptr,判断是否为空; - 若为空,用
std::async(std::launch::async, &get)启动异步任务,将返回的future存入新的shared_ptr,再通过原子交换操作更新全局指针(避免多线程竞态创建重复任务); - 若不为空,直接复用已有的
future; - 调用
future->get()等待结果就绪,所有任务将拿到同一个结果,无需重复调用get()。
- 原子加载当前的
完整代码示例
#include <iostream> #include <future> #include <memory> #include <atomic> #include <thread> #include <chrono> // 模拟耗时的get函数 std::string get() { std::cout << "正在执行耗时的get函数...\n"; std::this_thread::sleep_for(std::chrono::seconds(3)); // 模拟耗时操作 return "从get函数获取的数据"; } // 全局原子共享指针,存储future std::atomic<std::shared_ptr<std::future<std::string>>> g_future_ptr; // 任务类 class Task { public: void check() { // 原子加载当前future指针 auto future_ptr = g_future_ptr.load(); // 若指针为空,尝试创建新的异步任务 if (!future_ptr) { auto new_future = std::make_shared<std::future<std::string>>( std::async(std::launch::async, &get) ); // 原子交换:只有当前指针仍为空时才替换,避免多线程重复创建任务 if (g_future_ptr.compare_exchange_weak(future_ptr, new_future)) { std::cout << "任务" << std::this_thread::get_id() << "触发了get函数\n"; } else { // 交换失败,说明其他线程已创建任务,复用已有指针 future_ptr = g_future_ptr.load(); } } // 等待结果并获取 std::string result = future_ptr->get(); std::cout << "任务" << std::this_thread::get_id() << "获取到结果:" << result << "\n"; // 可将result写入Objs或直接使用 // Objs.text = result; } }; int main() { Task t1, t2, t3, t4; // 启动多个任务线程 std::thread th1(&Task::check, &t1); std::thread th2(&Task::check, &t2); std::thread th3(&Task::check, &t3); // 延迟启动第四个任务,模拟后续加入的任务 std::this_thread::sleep_for(std::chrono::seconds(1)); std::thread th4(&Task::check, &t4); th1.join(); th2.join(); th3.join(); th4.join(); return 0; }
关键细节说明
- 原子操作保护:
std::atomic<std::shared_ptr<...>>和compare_exchange_weak确保全局指针的读写是线程安全的,避免多个线程同时创建get()任务的竞态条件; - 强制异步执行:用
std::launch::async参数确保std::async创建独立线程执行get(),避免默认策略下可能的同步执行; - 结果复用:
future->get()第一次调用会阻塞至get()完成,后续调用直接返回已就绪的结果,不会重复执行耗时操作。
内容的提问来源于stack exchange,提问作者Poyen
相关产品推荐
相关产品推荐

