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

c++ 11 多线程支持 (std::packaged_task)

定义于头文件 <future>
template< class > class packaged_task; // 不定义  (1) (C++11 起) 

template< class R, class ...Args >
class packaged_task<R(Args...)>;                  (2) (C++11 起) 

类模板 std::packaged_task 包装任何可调用 (Callable) 目标(函数、 lambda 表达式、 bind 表达式或其他函数对象),使得能异步调用它。其返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。

正如 std::function , std::packaged_task 是多态、具分配器的容器:可在堆上或以提供的分配器分配存储的可调用对象。

构造函数

std::packaged_task<R(Args...)>::packaged_task
packaged_task() noexcept;   (1) (C++11 起) 

template <class F>
explicit packaged_task( F&& f ); (2) (C++11 起) 

template <class F, class Allocator>
explicit packaged_task( std::allocator_arg_t, const Allocator& a, F&& f );
(3) (C++11 起)  (C++17 前) 

packaged_task( const packaged_task& ) = delete; (4) (C++11 起) 

packaged_task( packaged_task&& rhs ) noexcept;  (5) (C++11 起) 

构造新的 std::packaged_task 对象。

1) 构造无任务且无共享状态的 std::packaged_task 对象。

2) 构造拥有共享状态和任务副本的 std::packaged_task 对象,以 std::forward<F>(f) 初始化副本。若 std::decay<F>::type 与 std::packaged_task<R(ArgTypes...)> 是同一类型,则此构造函数不参与重载决议。

3) 构造拥有共享状态和任务副本的 std::packaged_task 对象,以 std::forward<F>(f) 初始化副本。用提供的分配器分配存储任务所需的内存。 若 std::decay<F>::type 与 std::packaged_task<R(ArgTypes...)> 是同一类型,则此构造函数不参与重载决议。

4) 复制构造函数被删除, std::packaged_task 仅可移动。

5) 以 rhs 之前所占有的共享状态和任务构造 std::packaged_task ,令 rhs 留在无共享状态且拥有被移动后的任务的状态。

参数

f-要执行的可调用目标(函数、成员函数、 lambda 表达式、函数对象)
a-存储任务时所用的分配器
rhs-要移动的 std::packaged_task

异常

2) f 的复制/移动构造函数所抛的任何异常,而若内存分配失败则可能为 std::bad_alloc 。

3) f 的复制/移动构造函数,而若内存分配失败则有分配器的 allocate 函数所抛的任何异常。

4) (无)

析构函数

std::packaged_task<R(Args...)>::~packaged_task
~packaged_task();

抛弃共享状态并销毁存储的任务对象。

同 std::promise::~promise ,若在令共享状态就绪前抛弃它,则存储以 std::future_errc::broken_promise 为 error_code 的 std::future_error 异常。

参数

(无)

移动任务对象

std::packaged_task<R(Args...)>::operator=
packaged_task& operator=( const packaged_task& ) = delete; (1) (C++11 起) 

packaged_task& operator=( packaged_task&& rhs ) noexcept;  (2) (C++11 起) 

1) 复制赋值运算符被删除, std::packaged_task 仅可移动。

2) 若存在则释放共享状态,销毁先前保有的任务,并将 rhs 所占有的共享状态和任务移动到 *this 。令 rhs 无共享状态,并拥有被移动后的任务。

参数

rhs-移动来源的 std::packaged_task

检查任务对象是否拥有合法函数

std::packaged_task<R(Args...)>::valid
bool valid() const noexcept;  (C++11 起) 

检查 *this 是否拥有共享状态。

参数

(无)

返回值

若 *this 拥有共享状态则为 true ,否则为 false 。

交换二个任务对象

std::packaged_task<R(Args...)>::swap
void swap( packaged_task& other ) noexcept;   (C++11 起) 

交换 *this 与 other 的共享状态和存储的任务。

参数

other-要交换状态的 packaged_task

返回值

(无)

返回与承诺的结果关联的 std::future

std::packaged_task<R(Args...)>::get_future
std::future<R> get_future();    (C++11 起) 

返回与 *this 共享同一共享状态的 future

get_future 只能对每个 packaged_task 调用一次。

参数

(无)

返回值

与 *this 共享同一共享状态的 future

异常

遇到下列条件时为 std::future_error 。

  • 已通过调用 get_future 取得共享状态。设置 error_category 为 future_already_retrieved 。
  • *this 无共享状态。设置 error_category 为 no_state 。


执行函数

std::packaged_task<R(Args...)>::operator()
void operator()( ArgTypes... args );   (C++11 起) 

args 为参数调用存储的任务。任务返回值或任何抛出的异常被存储于共享状态。令共享状态就绪,并解除阻塞任何等待此操作的线程。

参数

args-调用时传递给存储任务的参数

返回值

(无)

异常

遇到下列条件时为 std::future_error :

  • 已调用存储的任务。设置 error_category 为 promise_already_satisfied 。
  • *this 无共享状态。设置 error_category 为 no_state 。

注意

operator() 的成功调用同步于对任何与 *this 共享其共享状态的 std::future 或 std::shared_future 的任何成员函数调用。

(C++14 前)

在共享状态已提供的同步保证外,无另外的同步保证。

(C++14 起)

 

重置状态,抛弃任何先前执行的存储结果

 std::packaged_task<R(Args...)>::reset
void reset();              (C++11 起) 

重置状态,抛弃先前执行的结果。构造共享状态。

等价于 *this = packaged_task(std::move(f)) ,其中 f 是存储的任务。

参数

(无)

返回值

(无)

异常

  • 若 *this 无共享状态则为 std::future_error 。设置 error_condition 为 no_state 。
  • 若无足够内存以分配新的共享状态则为 std::bad_alloc 。
  • packaged_task 的移动构造函数所抛的任何异常

执行函数,并确保结果仅在一旦当前线程退出时就绪

std::packaged_task<R(Args...)>::make_ready_at_thread_exit
void make_ready_at_thread_exit( ArgTypes... args );   (C++11 起) 

void make_ready_at_thread_exit( ArgTypes... args );

(C++11 起)

以转发的 args 为参数调用存储的任务。任务返回值或任何抛出的异常被存储于 *this 的共享状态。

仅在当前线程退出,并销毁所有线程局域存储期对象后,才令共享状态就绪。

参数

args-调用时传递给存储任务的参数

返回值

(无)

异常

遇到下列条件时为 std::future_error :

  • 已调用存储的任务。设置 error_category 为 promise_already_satisfied 。
  • *this 无共享状态。设置 error_category 为 no_state 。

调用示例

#include <future>
#include <iostream>
#include <chrono>
#include <thread>
#include <functional>
#include <utility>

void worker(std::future<void>& output)
{
    std::packaged_task<void(bool&)> my_task{ [](bool & done)
    {
        done = true;
    } };

    auto result = my_task.get_future();

    bool done = false;

    my_task.make_ready_at_thread_exit(done); // 立即执行任务

    std::cout << "worker: done = " << std::boolalpha << done << std::endl;

    auto status = result.wait_for(std::chrono::seconds(0));
    if (status == std::future_status::timeout)
    {
        std::cout << "worker: result is not ready yet" << std::endl;
    }

    output = std::move(result);
}


int main()
{
    std::future<void> result;

    std::thread{worker, std::ref(result)}.join();

    auto status = result.wait_for(std::chrono::seconds(0));
    if (status == std::future_status::ready)
    {
        std::cout << "main: result is ready" << std::endl;
    }
}

输出

特化 std::swap 算法

std::swap(std::packaged_task)
template< class Function, class... Args >
void swap( packaged_task<Function(Args...)> &lhs,
           packaged_task<Function(Args...)> &rhs ) noexcept;  (C++11 起) 

           packaged_task<Function(Args...)> &rhs ) noexcept;

(C++11 起)

为 std::packaged_task 特化 std::swap 算法。交换 lhsrhs 的状态。等效地调用 lhs.swap(rhs) 。

参数

lhs, rhs-要交换状态的 packaged_task

返回值

(无)

调用示例

#include <iostream>
#include <cmath>
#include <thread>
#include <future>
#include <functional>

// 避免对 std::pow 重载集消歧义的独有函数
int f(int x, int y)
{
    return std::pow(x, y);
}

void task_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';
}

void task_bind()
{
    std::packaged_task<int()> task(std::bind(f, 2, 11));
    std::future<int> result = task.get_future();

    task();

    std::cout << "task_bind:\t" << result.get() << '\n';
}

void task_thread()
{
    std::packaged_task<int(int, int)> task(f);
    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';
}

int main()
{
    task_lambda();
    task_bind();
    task_thread();
}

输出

 

相关文章:

  • Spring MVC注解Controller源码流程解析--定位HandlerMethod
  • 常用排序方法、sort的实现原理、快排的优化
  • centos7 离线安装httpd
  • Redis学习之路(三)--key键操作
  • 为什么这么多品牌迫切想要改变Logo?
  • 郁锦香、凯里亚德亮相“2022锦江行”,如何走出一条酒店破题之路
  • 拓展:Microsoft密钥类型说明
  • 基本 nosql 和 mongodb等数据库对比基本 nosql 和 mongodb等数据库对比
  • 使用打表法找规律
  • dockerkubernets篇(二十八)
  • 32. 最长有效括号 java解决
  • startActivityForResult废弃了,用Activity Result API吧
  • Go 学习笔记(87) — 函数式选项,初始化结构体对象可变参数
  • Android开发学习——2.Android开发环境准备
  • HNU工训中心STC-B学习板大作业-基于OLED模块的多功能MP4
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 2017 年终总结 —— 在路上
  • 2017届校招提前批面试回顾
  • 345-反转字符串中的元音字母
  • C语言笔记(第一章:C语言编程)
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • ES6--对象的扩展
  • JavaScript中的对象个人分享
  • KMP算法及优化
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • Objective-C 中关联引用的概念
  • Spark in action on Kubernetes - Playground搭建与架构浅析
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • vue自定义指令实现v-tap插件
  • XForms - 更强大的Form
  • 从0到1:PostCSS 插件开发最佳实践
  • 力扣(LeetCode)56
  • 使用agvtool更改app version/build
  • 探索 JS 中的模块化
  • 微信小程序实战练习(仿五洲到家微信版)
  • 我是如何设计 Upload 上传组件的
  • 新书推荐|Windows黑客编程技术详解
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • #### go map 底层结构 ####
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • (12)Linux 常见的三种进程状态
  • (27)4.8 习题课
  • (bean配置类的注解开发)学习Spring的第十三天
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (rabbitmq的高级特性)消息可靠性
  • (zhuan) 一些RL的文献(及笔记)
  • (第27天)Oracle 数据泵转换分区表
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (三十五)大数据实战——Superset可视化平台搭建
  • (算法)N皇后问题
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)