`std::packaged_task`、`std::thread` 和 `std::async` 的区别与联系
std::packaged_task、std::thread 和 std::async 的区别与联系
std::packaged_task、std::thread 和 std::async 都是 C++11 中提供的并发工具,用于执行任务并处理多线程操作。虽然它们都有类似的作用(并发执行任务),但在功能和使用方式上有显著区别。下面分别解释它们的特点,并说明它们的区别与联系。
1. std::packaged_task
特点:
- 封装可调用对象:
std::packaged_task能将一个可调用对象(如函数、lambda、函数对象)包装起来,使其能够异步执行。 - 返回结果:与任务关联的
std::future对象可以通过get()方法获取任务的执行结果。 - 任务执行方式:
std::packaged_task本身不负责执行任务,它只是一个包装器,任务的实际执行需要通过线程、std::async或直接调用。
使用场景:
- 适用于你想自己控制任务的执行过程,并且希望能够获得任务的返回值。
std::packaged_task提供了一种灵活的方式来包装任务,然后在不同的线程中执行它。
示例:
std::packaged_task<int(int)> task([](int x) { return x * x; });
std::future<int> result = task.get_future();
// 通过线程执行任务
std::thread t(std::move(task), 10);
t.join();
std::cout << "Result: " << result.get() << std::endl; // 输出: Result: 100
2. std::thread
特点:
- 手动管理线程:
std::thread是最基础的并发工具,用于创建并管理一个线程。你可以将任何可调用对象传递给线程,在线程中并发执行。 - 生命周期管理:线程的生命周期需要手动管理。你需要确保线程完成后调用
join()(等待线程结束)或detach()(分离线程)。 - 不返回结果:
std::thread只负责启动一个新线程,它本身没有机制直接返回线程执行的结果。如果需要返回结果,你需要配合std::future或其他同步机制使用。
使用场景:
- 适用于你希望直接管理线程的创建、执行和结束过程的场景。
std::thread提供了底层的并发控制能力。
示例:
std::thread t([] {
std::cout << "Hello from thread!" << std::endl;
});
t.join(); // 等待线程执行完毕
3. std::async
特点:
- 简化异步任务执行:
std::async用于异步执行任务。它自动管理线程的启动、执行和返回结果。 - 返回结果:
std::async返回一个std::future对象,允许你通过future.get()获取任务执行的结果。 - 可选择异步或同步:
std::async可以选择是否启动一个新线程(std::launch::async)或延迟执行(std::launch::deferred)。 - 自动管理:与
std::thread不同,std::async不需要手动join()或detach(),它会自动管理任务的执行和资源回收。
使用场景:
- 适用于你希望将任务提交给系统自动管理,并且无需手动控制线程的场景。
std::async提供了高层次的异步任务管理功能。
示例:
auto result = std::async([](int x) { return x * x; }, 10);
std::cout << "Result: " << result.get() << std::endl; // 输出: Result: 100
总结区别
| 特性 | std::packaged_task |
std::thread |
std::async |
|---|---|---|---|
| 任务封装 | 通过 packaged_task 包装可调用对象 |
将可调用对象传递给线程直接执行 | 提交任务,系统自动决定如何执行 |
| 返回结果 | 通过 std::future 获取结果 |
不提供直接的返回机制 | 返回 std::future,自动管理任务返回值 |
| 线程管理 | 需要手动启动线程来执行任务 | 需要手动创建、管理、结束线程 | 自动管理任务执行,提供异步和同步模式 |
| 资源管理 | 任务执行和线程生命周期分开管理 | 需要显式 join() 或 detach() 线程 |
自动管理资源,任务结束后自动回收资源 |
| 使用场景 | 灵活包装任务,控制任务执行过程 | 直接管理线程的生命周期和执行 | 简化的异步任务执行方式 |
通俗解释:
std::packaged_task:像打包一个任务的“快递包裹”,让你可以把任务交给别人(例如线程)去执行,然后你可以用“包裹单号”(std::future)去查询结果。std::thread:是“直接开车送快递”,你自己负责启动这个“车”(线程),并且需要决定什么时候让车停下来(join())或让车继续开(detach())。std::async:就像是找个“跑腿服务”,你把任务提交给跑腿系统,它会决定找人去做任务,并且在任务完成后,你可以直接通过“跑腿结果”(std::future)拿到结果。你不需要担心“车子”(线程)的管理。
`std::packaged_task`、`std::thread` 和 `std::async` 的区别与联系的更多相关文章
- C++并发编程之std::async(), std::future, std::promise, std::packaged_task
c++11中增加了线程,使得我们可以非常方便的创建线程,它的基本用法是这样的: void f(int n); std::thread t(f, n + 1); t.join(); 但是线程毕竟是属于比 ...
- c++ 如何获取多线程的返回值?(std::thread ,std::async)
//简单的 c++11 线程,简单方便,成员函数随便调用,非成员函数也一样,如需要获取返回时,请自行使用条件变量 std::thread run([&](){ //执行一些耗时的操作 retu ...
- C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)
上一讲<C++11 并发指南四(<future> 详解一 std::promise 介绍)>主要介绍了 <future> 头文件中的 std::promise 类, ...
- C++11之std::future和std::promise和std::std::packaged_task
为什么C++11引入std::future和std::promise?C++11创建了线程以后,我们不能直接从thread.join()得到结果,必须定义一个变量,在线程执行时,对这个变量赋值,然后执 ...
- C++并发低级接口:std::thread和std::promise
std::thread和std::promise 相比std::async,std::thread就原始多了.thread一定会创建新线程(而不是像async那样创建的时候可能不会,后面才创建新线程( ...
- boost和std中的thread的引用参数
boost 1.60.0 先上代码: #include <boost/thread.hpp> #include <iostream> void add(int &i) ...
- could not deduce template argument for 'const std::_Tree<_Traits> &' from 'const std::string'
VS2008, 写一个简单的demo的时候出现了这个: 1>------ Build started: Project: GetExportTable, Configuration: Relea ...
- std::u32string conversion to/from std::string and std::u16string
I need to convert between UTF-8, UTF-16 and UTF-32 for different API's/modules and since I know have ...
- c++11 标准库函数 std::move 和 完美转发 std::forward
c++11 标准库函数 std::move 和 完美转发 std::forward #define _CRT_SECURE_NO_WARNINGS #include <iostream> ...
- .NET多线程(Thread,ThreadPool,Task,Async与Await)
.NET多线程是什么? 进程与线程 进程是一种正在执行的程序. 线程是程序中的一个执行流. 多线程是指一个程序中可以同时运行多个不同的线程来执行不同的任务. .NET中的线程 Thread是创建和控制 ...
随机推荐
- c++17 structure binding test
1 /*test for struct binding*/ 2 3 #include <string> 4 #include <iostream> 5 using namesp ...
- innodb存储引擎了解
mysql常用的存储引擎分为innodb和myisam 其中innodb具有支持事务,执行行级锁,支持MVCC,外键,自动增长列,崩溃恢复等特性.并且mysql在5.5.5之后是数据的默认存储引擎 文 ...
- Python+selenium编写第一个UI自动化脚本
python UI自动化前提:①python需要安装selenium模块 ②下载浏览器驱动 1.安装selenium模块 先确认本地是否安装selenium模块,没有的话点击右边的添加按钮" ...
- 【JavaScript】精度损失问题
参卡博客: https://blog.csdn.net/azl397985856/article/details/99148969/
- 【导出Excel】 JS的Excel导出库 Export2Excel
Export2Excel库默认放在ElementUI-Admin项目的src/vendor包中 不是通过package.json安装的依赖 这里直接贴库的源码: /* eslint-disable * ...
- 【JS】01 JavaScript概述
感觉上来谈这个前端,结构的部分是使用了标签语言定义了页面的文档内容 但是XML和HTML的功能完全相反,XML被用于存储信息,而HTML则用于定义网页结构,辅助其他内容渲染 然后C3又可以通过选择器这 ...
- 如何在通用异常处理时获取到方法名称(获取注解参数JoinPoint)
1.背景 很多时候我们在梳理公共异常时,需要获取到接口的而具体名称,便于很好的提示是那个接口错误了 2.实现逻辑 1.在controller方法上的注解上写方法名称,一般使用了swagger都有方法名 ...
- 痞子衡嵌入式:探析i.MXRT1050在GPIO上增加RC延时电路后导致边沿中断误触发问题(上篇)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是i.MXRT1050在GPIO上增加RC延时电路后导致边沿中断误触发问题探析. 前段时间有一个 RT1052 客户反馈了一个有趣的问题, ...
- SMU Summer 2023 Contest Round 1
SMU Summer 2023 Contest Round 1 A. The Contest 当 \(m\) 为 \(0\) 和 完成时间大于最后一个时刻时,说明都无法在规定条件内完成,输出\(-1\ ...
- SMU Spring 2023 Contest Round 5(2023 (ICPC) Jiangxi Provincial Contest -- Official Contest)
题目链接 Problem A. Drill Wood to Make Fire S * V >= n即可 #include<bits/stdc++.h> #define int lo ...