千家信息网

C++11中如何使用std::packaged_task

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要介绍C++11中如何使用std::packaged_task,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!C++11中的std::packaged_task是个模板
千家信息网最后更新 2026年11月03日C++11中如何使用std::packaged_task

这篇文章主要介绍C++11中如何使用std::packaged_task,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

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 #include #include #include #include #include #include #include  #include #include #include #include  namespace future_ { ///////////////////////////////////////////////////////////// reference: http://www.cplusplus.com/reference/future/packaged_task/int test_packaged_task_1(){ { // constructor/get_future/operator=/valid std::packaged_task foo; // default-constructed std::packaged_task bar([](int x) { return x * 2; }); // initialized  foo = std::move(bar); // move-assignment std::cout << "valid: " << foo.valid() << "\n"; std::future 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 tsk([](int x) { return x * 3; }); // package task  std::future 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 tsk(countdown); // set up packaged_task std::future 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_taskint test_packaged_task_2(){{ // lambda std::packaged_task task([](int a, int b) { return std::pow(a, b);}); std::future result = task.get_future();  task(2, 9); std::cout << "task_lambda:\t" << result.get() << '\n';} { // bind std::packaged_task task(std::bind([](int x, int y) { return std::pow(x, y); }, 2, 11)); std::future result = task.get_future();  task(); std::cout << "task_bind:\t" << result.get() << '\n';} { // thread std::packaged_task task([](int x, int y) { return std::pow(x, y); }); std::future 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 task(std::move(DBDataFetcher()));  // Fetch the associated future<> from packaged_task<> std::future 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-asyncint 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 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

以上是"C++11中如何使用std::packaged_task"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!

对象 状态 函数 存储 任务 准备 关联 成员 内容 模板 参考 移动 相同 两个 代码 拷贝 指针 篇文章 类型 线程 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 科技互联网企业 安徽鑫晟辉互联网科技 极限挑战互联网科技 掌上梦互联网科技 互联网高科技股票 佰商互联网科技有限公司 多迪互联网科技有限公司 科技类的互联网平台 美国互联网前沿科技 以后互联网后是啥科技 宁夏众和广鑫互联网科技有限公司 互联网科技项目计划书材料类 互联网科技革命什么开始 民营互联网公司国防科技 特约风豹互联网科技为什么扣费 烟台灵鸽互联网科技有限公司 科技信息时代互联网发展 广州三三互联网科技有限公司 广西泛欧互联网科技有限公司 深圳互联网科技园地址 广州紫鲸互联网科技有限公司 互联网科技有限公司图片 壹账通互联网科技 科技伦理 互联网公司 深圳育鹏互联网科技有限公司招聘 健康食品互联网创新科技园项目 易企秀互联网科技是做什么的 陕西九四连强互联网科技有限公司 安徽零酒互联网科技有限公司 科技美学互联网 艺术
0