深入理解C++11中的std::packaged_task

什么是std::packaged_task?
std::packaged_task是一个模板类,用于打包任务(如可调用对象、函数、lambda表达式、bind表达式或者其他函数对象),以便异步地执行它,并获取其结果。它与std::future和std::promise一起构成了C++标准库中异步编程的基础。std::packaged_task的目的是为了封装任务以便在线程之间传递,实现任务的异步处理。

std::packaged_task的基本使用
std::packaged_task封装的函数的计算结果会通过与之关联的std::future::get获取(可以在其它线程中异步获取)。关联的std::future可以通过std::packaged_task::get_future获取,该方法只能调用一次,多次调用会触发std::future_error异常。

和std::function类似,std::packaged_task是一个多态的、能够感知内存分配的容器:存储的可调用目标可以分配到堆上,也可以通过提供的内存分配器定义存储方式。

使用场景
异步任务执行:将任务封装起来,并在稍后或在A线程中执行它。在B线程获取结果。
线程池:在实现线程池时,可以使用std::packaged_task封装任务,并将其提交到线程池中。
任务取消和重试:通过将任务封装在std::packaged_task中,可以更方便地管理任务的取消和重试。

代码示例
以下是一个简单的示例,展示了如何使用std::packaged_task和std::future进行异步任务处理:

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

int compute(int a, int b) {
    std::this_thread::sleep_for(std::chrono::seconds(5)); // 模拟长时间计算
    return a + b;
}

void task1() {
    std::packaged_task<int(int, int)> task(compute);
    std::future<int> result = task.get_future();
    std::thread t(std::move(task), 5, 4);
    
    std::cout << "Waiting for result..." << std::endl;
    std::cout << "Result: " << result.get() << std::endl;
    
    t.join();
}

int main() {
    task1();
    return 0;
}

在这个示例中:
创建了一个std::packaged_task对象,并封装了compute函数。
获取与任务关联的std::future对象。
在一个新的线程中执行任务。
等待并输出结果。
确保线程结束。
使用std::bind和std::packaged_task
std::bind用于创建一个新的可调用对象,将函数与部分或全部参数绑定,从而生成一个新的函数对象或函数指针。这个新对象可以存储并在稍后调用,而不需要再次提供参数。结合std::packaged_task和std::bind可以方便地封装和调度任务。

代码示例

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

int packagedTaskMethod(int val, std::string str) {
    std::cout << "run packagedTaskMethod: val = " << val << " , str = " << str << std::endl;
    return 555999;
}

void task2() {
    auto boundTask = std::bind(packagedTaskMethod, 42, std::placeholders::_1);
    std::packaged_task<int(std::string)> task1(boundTask);
    
    std::future<int> ret1 = task1.get_future();
    std::thread t(std::move(task1), "hhh");
    
    std::cout << "Result: " << ret1.get() << std::endl;
    t.join();
}

int main() {
    task2();
    return 0;
}

在这个示例中:
使用std::bind将packagedTaskMethod的部分参数固定下来,生成一个新的可调用对象。
将该对象封装到std::packaged_task中。
在一个新的线程中执行任务,并传递参数。
等待并输出结果。
确保线程结束。

总结
通过std::packaged_task和std::future,可以轻松地在不同线程间传递任务和获取结果,实现并发编程。同时,结合std::bind可以简化参数管理和任务调度,提供更高的灵活性和可读性。这些特性使得std::packaged_task在异步编程中非常有用,尤其是在复杂的任务管理和多线程环境中。

相关推荐

  1. 深入理解C++11std::packaged_task

    2024-07-14 17:54:05       21 阅读
  2. 深入理解C++inline函数

    2024-07-14 17:54:05       28 阅读
  3. 深入理解和运用C语言Break语句

    2024-07-14 17:54:05       49 阅读
  4. 深入理解与运用C语言Continue关键字

    2024-07-14 17:54:05       52 阅读
  5. 深入理解C++指针与引用

    2024-07-14 17:54:05       57 阅读
  6. 深入理解C#事件驱动编程

    2024-07-14 17:54:05       44 阅读
  7. 深入理解C语言联合体(union)

    2024-07-14 17:54:05       42 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-14 17:54:05       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-14 17:54:05       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-14 17:54:05       57 阅读
  4. Python语言-面向对象

    2024-07-14 17:54:05       68 阅读

热门阅读

  1. 华为 NAT 技术介绍及配置

    2024-07-14 17:54:05       21 阅读
  2. prompt第三讲-PromptTemplate

    2024-07-14 17:54:05       17 阅读
  3. 微信小程序的目录结构

    2024-07-14 17:54:05       26 阅读
  4. Nmap端口扫描工具

    2024-07-14 17:54:05       22 阅读
  5. 如何设计一个C语言面向结构体的内存数据库

    2024-07-14 17:54:05       19 阅读
  6. NSIS 之 NsDialogs 常见问题解答

    2024-07-14 17:54:05       20 阅读
  7. Nginx配置缺少导致CSS不起作用

    2024-07-14 17:54:05       21 阅读