C++11中std::packaged_task的使用详解
作者:fengbingchun 发布时间:2022-03-12 20:08:23
C++11中的std::packaged_task是个模板类。std::packaged_task包装任何可调用目标(函数、lambda表达式、bind表达式、函数对象)以便它可以被异步调用。它的返回值或抛出的异常被存储于能通过std::future对象访问的共享状态中。
std::packaged_task类似于std::function,但是会自动将其结果传递给std::future对象。
std::packaged_task对象内部包含两个元素:(1).存储的任务(stored task)是一些可调用的对象(例如函数指针、成员或函数对象的指针)( A stored task, which is some callable object (such as a function pointer, pointer to member or function object))。(2).共享状态,它可以存储调用存储的任务(stored task)的结果,并可以通过std::future进行异步访问(A shared state, which is able to store the results of calling the stored task and be accessed asynchronously through a future)。
通过调用std::packaged_task的get_future成员将共享状态与std::future对象关联。调用之后,两个对象共享相同的共享状态:(1).std::packaged_task对象是异步提供程序(asynchronous provider),应通过调用存储的任务(stored task)在某个时刻将共享状态设置为就绪。(2).std::future对象是一个异步返回对象,可以检索共享状态的值,并在必要时等待其准备就绪。
共享状态的生存期至少要持续到与之关联的最后一个对象释放或销毁为止。
std::packaged_task不会自己启动,你必须调用它(A packaged_task won't start on it's own, you have to invoke it)。
std::future介绍参考:https://www.jb51.net/article/179229.htm
模板类std::packaged_task成员函数包括:
1. 构造函数:(1).默认构造函数:无共享状态无存储任务(no shared state and no stored task)情况下初始化对象。(2). initialization constructor:该对象具有共享状态,且其存储的任务由fn初始化。(3). initialization constructor with allocator。(4).禁用拷贝构造。(5).支持移动构造。
2. 析构函数:(1).放弃(abandon)共享状态并销毁packaged_task对象。(2). 如果有其它future对象关联到同一共享状态,则共享状态本身不会被销毁。(3). 如果packaged_task对象在共享状态准备就绪前被销毁,则共享状态自动准备就绪并包含一个std::future_error类型的异常。
3. get_future函数:(1).返回一个与packaged_task对象的共享状态关联的std::future对象。(2).一旦存储的任务被调用,返回的std::future对象就可以访问packaged_task对象在共享状态上设置的值或异常。(3).每个packaged_task共享状态只能被一个std::future对象检索(Only one future object can be retrieved for each packaged_task shared state)。(4).调用此函数后,packaged_task应在某个时候使其共享状态准备就绪(通过调用其存储的任务),否则将在销毁后自动准备就绪并包含一个std::future_error类型的异常。
4. make_ready_at_thread_exit函数:在线程退出时才使共享状态ready而不是在调用完成后就立即ready。
5. operator=:(1).禁用拷贝赋值。(2).支持移动赋值。
6. operator():(1).call stored task。(2).如果对存储任务的调用成功完成或抛出异常,则返回的值或捕获的异常存储在共享状态,共享状态准备就绪(解除阻塞当前等待它的所有线程)。
7. reset函数:(1).在保持相同存储的任务的同时,以新的共享状态重置对象。(2).允许再次调用存储的任务。(3).与对象关联的之前的共享状态被放弃(就像packaged_task被销毁了一样)。(4).在内部,该函数的行为就像是移动赋值了一个新构造的packaged_task一样(Internally, the function behaves as if move-assigned a newly constructed packaged_task (with its stored task as argument))。
8. swap函数/非成员模板函数swap:交换共享状态和存储的任务(stored task)。
9. valid函数:检查packaged_task对象是否具有共享状态。
详细用法见下面的测试代码,下面是从其他文章中copy的测试代码,部分作了调整,详细内容介绍可以参考对应的reference:
#include "future.hpp"
#include <iostream>
#include <future>
#include <chrono>
#include <utility>
#include <thread>
#include <functional>
#include <memory>
#include <exception>
#include <numeric>
#include <vector>
#include <cmath>
#include <string>
namespace future_ {
///////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/future/packaged_task/
int test_packaged_task_1()
{
{ // constructor/get_future/operator=/valid
std::packaged_task<int(int)> foo; // default-constructed
std::packaged_task<int(int)> bar([](int x) { return x * 2; }); // initialized
foo = std::move(bar); // move-assignment
std::cout << "valid: " << foo.valid() << "\n";
std::future<int> ret = foo.get_future(); // get future
std::thread(std::move(foo), 10).detach(); // spawn thread and call task
int value = ret.get(); // wait for the task to finish and get result
std::cout << "The double of 10 is " << value << ".\n";
}
{ // reset/operator()
std::packaged_task<int(int)> tsk([](int x) { return x * 3; }); // package task
std::future<int> fut = tsk.get_future();
tsk(33);
std::cout << "The triple of 33 is " << fut.get() << ".\n";
// re-use same task object:
tsk.reset();
fut = tsk.get_future();
std::thread(std::move(tsk), 99).detach();
std::cout << "Thre triple of 99 is " << fut.get() << ".\n";
}
{ // constructor/get_future
auto countdown = [](int from, int to) {
for (int i = from; i != to; --i) {
std::cout << i << '\n';
std::this_thread::sleep_for(std::chrono::seconds(1));
}
std::cout << "Lift off!\n";
return from - to;
};
std::packaged_task<int(int, int)> tsk(countdown); // set up packaged_task
std::future<int> ret = tsk.get_future(); // get future
std::thread th(std::move(tsk), 5, 0); // spawn thread to count down from 5 to 0
int value = ret.get(); // wait for the task to finish and get result
std::cout << "The countdown lasted for " << value << " seconds.\n";
th.join();
}
return 0;
}
///////////////////////////////////////////////////////////
// reference: https://en.cppreference.com/w/cpp/thread/packaged_task
int test_packaged_task_2()
{
{ // lambda
std::packaged_task<int(int, int)> task([](int a, int b) { return std::pow(a, b);});
std::future<int> result = task.get_future();
task(2, 9);
std::cout << "task_lambda:\t" << result.get() << '\n';
}
{ // bind
std::packaged_task<int()> task(std::bind([](int x, int y) { return std::pow(x, y); }, 2, 11));
std::future<int> result = task.get_future();
task();
std::cout << "task_bind:\t" << result.get() << '\n';
}
{ // thread
std::packaged_task<int(int, int)> task([](int x, int y) { return std::pow(x, y); });
std::future<int> result = task.get_future();
std::thread task_td(std::move(task), 2, 10);
task_td.join();
std::cout << "task_thread:\t" << result.get() << '\n';
}
return 0;
}
///////////////////////////////////////////////////////////
// reference: https://thispointer.com/c11-multithreading-part-10-packaged_task-example-and-tutorial/
struct DBDataFetcher {
std::string operator()(std::string token)
{
// Do some stuff to fetch the data
std::string data = "Data From " + token;
return data;
}
};
int test_packaged_task_3()
{
// Create a packaged_task<> that encapsulated a Function Object
std::packaged_task<std::string(std::string)> task(std::move(DBDataFetcher()));
// Fetch the associated future<> from packaged_task<>
std::future<std::string> result = task.get_future();
// Pass the packaged_task to thread to run asynchronously
std::thread th(std::move(task), "Arg");
// Join the thread. Its blocking and returns when thread is finished.
th.join();
// Fetch the result of packaged_task<> i.e. value returned by getDataFromDB()
std::string data = result.get();
std::cout << data << std::endl;
return 0;
}
///////////////////////////////////////////////////////////
// reference: https://stackoverflow.com/questions/18143661/what-is-the-difference-between-packaged-task-and-async
int test_packaged_task_4()
{
// sleeps for one second and returns 1
auto sleep = []() {
std::this_thread::sleep_for(std::chrono::seconds(1));
return 1;
};
{ // std::packaged_task
// >>>>> A packaged_task won't start on it's own, you have to invoke it
std::packaged_task<int()> task(sleep);
auto f = task.get_future();
task(); // invoke the function
// You have to wait until task returns. Since task calls sleep
// you will have to wait at least 1 second.
std::cout << "You can see this after 1 second\n";
// However, f.get() will be available, since task has already finished.
std::cout << f.get() << std::endl;
}
{ // std::async
// >>>>> On the other hand, std::async with launch::async will try to run the task in a different thread :
auto f = std::async(std::launch::async, sleep);
std::cout << "You can see this immediately!\n";
// However, the value of the future will be available after sleep has finished
// so f.get() can block up to 1 second.
std::cout << f.get() << "This will be shown after a second!\n";
}
return 0;
}
} // namespace future_
GitHub:https://github.com/fengbingchun/Messy_Test
来源:https://blog.csdn.net/fengbingchun/article/details/104127352


猜你喜欢
- 目录前言基础组件工作流程初步使用详细流程获取 MapperProxy 对象缓存执行方法构造参数获取需要执行的 SQL 对象执行 SQL 语句
- 效果图如下所示:一、shape 样式:(在drawable新建--》new--》Drawable resource file 在父级标签se
- 直接用英文逗号分隔就可以了,比如:inerface IHello { String sayHello(String name);
- Android资源文件大致可以分为两种:第一种是res目录下存放的可编译的资源文件:这种资源文件系统会在R.java里面自动生成该资源文件的
- 在学习java中的collection时注意到,collection层次的根接口Collection实现了Iterable<T>
- 前言最近搭建的springbootboot的网关,配置请求路径,竟然没有生效现象配置文件如下:启动类,控制台打印的结果如下:我随便更换端口都
- java 指定某个jdk版本方法指定某个jdk版本方法背景:当我们在同一台机器上运行多个Java程序,但是所需的java版本不同,此时就需要
- 在很多其他框架中,比如Python的Flask、node.js的KOA,Controller要想能够响应前端的请求都需要我们主动去注册到应用
- 本文实例讲述了Java文本文件操作方法。分享给大家供大家参考。具体分析如下:最初Java是不支持对文本文件的处理的,为了弥补这个缺憾而引入了
- 介绍什么是ThreadLocal?ThreadLocal叫做线程变量,用于在多线程环境下创建线程本地变量。通俗的讲,ThreadLocal可
- 基于Java语言实现Socket通信由于近日项目需求,需要在服务器中增加Socket通信的功能,接收硬件设备发送的心跳包和相关数据,因此又重
- 什么是异常?最简单的,看一个代码示例:public static void main(String[] args) { &nb
- 这里主要利用API函数Animate Window实现窗体左右,上下,扩展,淡入滑动或滚动动画效果,步骤如下:1.新建窗体,使用2个Grou
- 分栏是报刊、书籍、杂志常用的排版样式,它不仅能方便阅读,同时也能增加页面的美观度。本文将介绍如何在Java应用程序中给Word文档添加多个栏
- 官方文档 8.0Spring为不同缓存做了一层抽象,这里通过阅读文档以及源码会对使用以及原理做一些学习笔记。1.简介
- 功能实现:1、图片加载类ImageLoader实现:1)用阻塞队列存储要图片:BlockingQueue images = new Arra
- 简介JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation。在任何时候,当你要处理一个应用程序的业务逻
- 一、项目简述(+需求文档+PPT)功能: 主页显示热销商品;所有商品展示,可进行商品搜索;点 击商品进入商品详情页,显示库存,具有立即购买和
- 本篇介绍我们如何利用selenium 来操作各种页面元素阅读目录链接(link)输入框 textbox按钮(Button)下拉选择框(Sel
- 今天传图片,用的base64字符串,POST方法,前端传送的时候总是莫名其妙的崩溃,去网上搜了半天,以为是文件大小被限制了,但是我这个是字符