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

C++ 第三阶段 并发与异步 - 第二节:异步任务(std::async)

目录

一、std::async 概述

1. std::async 的定义

二、std::async 的基本用法

1. 基本语法

(1) 函数调用

(2) Lambda 表达式

三、执行策略详解

1. std::launch::async

2. std::launch::deferred

3. 默认策略(std::launch::any)

四、std::future:异步结果管理

1. 获取结果的方法

五、异常处理与安全性

1. 异步任务中的异常

2. 避免资源泄漏

六、最佳实践

1. 显式指定执行策略

2. 合理使用超时机制

3. 避免共享状态竞争

七、常见问题与解决方案

1. 任务未执行

2. 性能问题

3. 异常未捕获

八、示例代码汇总

示例 1:基础异步任务

示例 2:超时等待

示例 3:多异步任务并行

九、总结

1. std::async 的核心优势

2. 适用场景

3. 后续学习方向

C++从入门到入土学习导航_c++学习进程-CSDN博客


一、std::async 概述

1. std::async 的定义

std::async 是 C++11 引入的高级异步任务管理工具,用于启动异步任务并返回一个 std::future 对象。其核心功能包括:

  • 自动管理线程:根据策略决定是否立即创建新线程或延迟执行。
  • 异步任务结果获取:通过 std::future 提供阻塞或非阻塞方式获取结果。
  • 灵活的执行策略:支持 std::launch::async(立即执行)和 std::launch::deferred(延迟执行)。

二、std::async 的基本用法

1. 基本语法

template<class Function, class... Args>
std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>> 
async(Function&& f, Args&&... args);
(1) 函数调用
#include <iostream>
#include <future>int computeSum(int a, int b) {return a + b;
}int main() {auto future = std::async(computeSum, 3, 4); // 默认策略std::cout << "Result: " << future.get() << std::endl; // 阻塞直到结果可用return 0;
}
(2) Lambda 表达式
auto future = std::async([]() {return "Hello, async!";
});
std::cout << future.get() << std::endl;

三、执行策略详解

1. std::launch::async

  • 立即启动新线程:任务在独立线程中执行。
  • 适用场景:需要并行执行耗时操作(如计算、I/O)。
  • 示例
    auto future = std::async(std::launch::async, []() {std::this_thread::sleep_for(std::chrono::seconds(2));return 42;
    });

2. std::launch::deferred

  • 延迟执行:任务在调用 get() 或 wait() 时执行(可能在当前线程)。
  • 适用场景:轻量级任务或无需并行的场景。
  • 示例
    auto future = std::async(std::launch::deferred, []() {return "Deferred task";
    });
    std::cout << future.get() << std::endl; // 此时任务执行

3. 默认策略(std::launch::any

  • 由实现决定:可能选择异步或延迟策略(具体行为依赖编译器和平台)。
  • 示例
    auto future = std::async([]() { return 100; }); // 实现决定策略

四、std::future:异步结果管理

1. 获取结果的方法

  • get():阻塞当前线程,直到任务完成并返回结果。注意get() 只能调用一次。

    auto future = std::async([]() { return 5 * 5; });
    std::cout << "Result: " << future.get() << std::endl;
  • wait():阻塞直到任务完成(不返回结果)。

    auto future = std::async([]() { std::this_thread::sleep_for(1s); });
    future.wait(); // 等待任务完成
  • wait_for() / wait_until():带超时的等待。

    auto future = std::async([]() { std::this_thread::sleep_for(2s); });
    auto status = future.wait_for(1s); // 超时检查
    if (status == std::future_status::ready) {std::cout << "Task completed!" << std::endl;
    } else {std::cout << "Timeout!" << std::endl;
    }

五、异常处理与安全性

1. 异步任务中的异常

  • 如果异步任务抛出异常,调用 future.get() 时会重新抛出该异常。
  • 示例
    auto future = std::async([]() {throw std::runtime_error("Async error!");
    });
    try {future.get(); // 抛出异常
    } catch (const std::exception& e) {std::cerr << "Caught: " << e.what() << std::endl;
    }

2. 避免资源泄漏

  • 必须调用 get() 或 wait():未调用会导致线程资源未释放。
  • 示例
    {auto future = std::async([]() { return 100; });future.get(); // 必须调用
    }

六、最佳实践

1. 显式指定执行策略

  • 避免默认策略的不确定性:优先使用 std::launch::async
    auto future = std::async(std::launch::async, heavyComputation, args...);

2. 合理使用超时机制

  • 防止无限阻塞:结合 wait_for() 或 wait_until()
    auto future = std::async(std::launch::async, longRunningTask);
    if (future.wait_for(5s) == std::future_status::ready) {processResult(future.get());
    } else {std::cerr << "Task timeout!" << std::endl;
    }

3. 避免共享状态竞争

  • 使用锁或原子类型:保护共享数据。
    std::mutex mtx;
    auto task1 = std::async([&]() {std::lock_guard<std::mutex> lock(mtx);sharedData++;
    });

七、常见问题与解决方案

1. 任务未执行

  • 原因:使用 std::launch::deferred 但未调用 get() 或 wait()
  • 解决方案:显式调用 get()
    auto future = std::async(std::launch::deferred, []() { return 10; });
    future.get(); // 必须调用

2. 性能问题

  • 原因:频繁创建短生命周期线程。
  • 解决方案:使用线程池(需自行实现)。
    // 示例:伪代码,实际需实现线程池
    class ThreadPool {
    public:// 构造函数:启动指定数量的工作线程ThreadPool(size_t numThreads) : stop(false) {for (size_t i = 0; i < numThreads; ++i) {workers.emplace_back([this] { this->worker(); });}}// 析构函数:停止所有线程,确保资源释放~ThreadPool() {{std::unique_lock<std::mutex> lock(queue_mutex);stop = true;}condition.notify_all();for (std::thread& worker : workers) {if (worker.joinable()) {worker.join();}}}// 提交任务:支持任意可调用对象 + 参数,返回 future 结果template<typename F, typename... Args>auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> {using return_type = typename std::result_of<F(Args...)>::type;auto task = std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));{std::unique_lock<std::mutex> lock(queue_mutex);tasks.push([task]() { (*task)(); });}condition.notify_one();return task->get_future();}private:// 工作线程主循环:等待任务并执行void worker() {while (true) {std::function<void()> task;{std::unique_lock<std::mutex> lock(queue_mutex);condition.wait(lock, [this] { return stop || !tasks.empty(); });if (stop && tasks.empty()) return;task = std::move(tasks.front());tasks.pop();}task();}}std::vector<std::thread> workers;           // 工作线程池std::queue<std::function<void()>> tasks;    // 任务队列std::mutex queue_mutex;                     // 保护任务队列的互斥锁std::condition_variable condition;          // 同步任务队列的条件变量bool stop;                                   // 是否停止线程池
    };

3. 异常未捕获

  • 原因:未处理异步任务的异常。
  • 解决方案:在 get() 调用时捕获异常。
    try {future.get();
    } catch (...) {std::cerr << "Unexpected error!" << std::endl;
    }

八、示例代码汇总

示例 1:基础异步任务

#include <iostream>
#include <future>
#include <thread>int computeSquare(int x) {return x * x;
}int main() {auto future = std::async(std::launch::async, computeSquare, 5);std::cout << "Computing square..." << std::endl;std::cout << "Result: " << future.get() << std::endl;return 0;
}

示例 2:超时等待

#include <iostream>
#include <future>
#include <chrono>void longRunningTask() {std::this_thread::sleep_for(std::chrono::seconds(3));
}int main() {auto future = std::async(std::launch::async, longRunningTask);std::cout << "Waiting for task..." << std::endl;auto status = future.wait_for(std::chrono::seconds(2));if (status == std::future_status::ready) {std::cout << "Task completed!" << std::endl;} else {std::cout << "Task not ready yet!" << std::endl;}return 0;
}

示例 3:多异步任务并行

#include <iostream>
#include <future>
#include <vector>
#include <thread>int computeSum(int a, int b) {return a + b;
}int main() {std::vector<std::future<int>> futures;for (int i = 0; i < 5; ++i) {futures.push_back(std::async(std::launch::async, computeSum, i, i * 2));}for (auto& future : futures) {std::cout << "Result: " << future.get() << std::endl;}return 0;
}

九、总结

1. std::async 的核心优势

  • 简化线程管理:自动处理线程创建和销毁。
  • 灵活的执行策略:支持异步和延迟两种模式。
  • 结果安全获取:通过 std::future 提供阻塞和非阻塞接口。

2. 适用场景

  • 后台任务:如文件读写、网络请求、计算密集型任务。
  • 并行处理:同时执行多个独立任务。
  • 异步结果获取:避免主线程阻塞,提升程序响应性。

3. 后续学习方向

  • 高级同步机制:如 std::condition_variablestd::atomic
  • 线程池实现:优化 std::async 的性能瓶颈。
  • 异步任务链:结合 std::future 和 std::promise 实现复杂任务依赖。

通过掌握 std::async,开发者可以高效管理异步任务,提升程序的并发性能和响应能力,为构建复杂的多线程应用打下坚实基础。

http://www.lqws.cn/news/541495.html

相关文章:

  • 在docker容器中安装docker服务,基于fuse-overlayfs进行overlay挂载,而不是vfs
  • HarmonyOS NEXT仓颉开发语言实现画板案例
  • MySQL 离线安装MariaDB
  • SYSCFG 时钟在 GD32F4 系列微控制器中的作用
  • Layer by Layer: Uncovering Hidden Representations in Language Models
  • 当前最好的0样本文本转语音是哪个模型?
  • SpringCloud系列(38)--SpringCloud Gateway实现动态路由
  • 2024百度之星:BD202404 110串
  • JDY-23蓝牙模块与电脑的连接方式
  • 从0开始学习计算机视觉--Day04--损失函数
  • 杭州西湖断桥不断:3D扫描还原‘残雪‘视觉骗局
  • 在反向代理环境下精准获取客户端真实 IP 的最佳实践
  • Linux journal 日志大小限制与管理详解
  • vue-27(实践练习:将现有组件重构为使用组合式 API)
  • 七天学会SpringCloud分布式微服务——04——Nacos配置中心
  • 便携式水质检测仪的功能
  • 基于 SpringBoot+Vue 的台球厅管理系统的设计与实现(毕业论文)
  • [ linux-系统 ] 磁盘与文件系统
  • 排查 WebView 中 touch、click 事件失效:移动端调试过程详解
  • PIXHAWK(ardupilot4.52)NMEA的解析bug
  • EXCEL数据报表
  • 接口自动化测试框架(pytest+allure+aiohttp+用例自动生成)
  • 【Python基础】05 Python视频压缩技术深度解析
  • 商务创业项目策划计划书PPT模版
  • [Meetily后端框架] 配置指南 | 后端API网关 | API文档体系
  • VB.NET,C#字典对象来保存用户数据,支持大小写
  • Unreal引擎——Chaos物理引擎(不)详解
  • 官方 Linker Scripts 语法和规则解析(2)
  • 《算力迁徙:WebAssembly如何将C++算法炼成前端》
  • 临床项目范围管理:确保项目聚焦与成功交付