个人知识库 个人知识库
首页
关于
  • C语言
  • CPlusPlus
  • Linux
  • PHP
  • Nginx
  • MySQL
  • Redis
  • Docker
  • Kubernetes
  • SRS
阅读
常用工具
  • 分类
  • 标签
  • 归档
GitHub

Agnes001

坚持是一件很伟大的事业
首页
关于
  • C语言
  • CPlusPlus
  • Linux
  • PHP
  • Nginx
  • MySQL
  • Redis
  • Docker
  • Kubernetes
  • SRS
阅读
常用工具
  • 分类
  • 标签
  • 归档
GitHub
  • C语言

  • CPlusPlus

    • 基础特性

    • vs2019设置
    • C++11特性

    • 并发编程

      • 并发编程
      • chrono
      • thread
      • mutex
      • condition_varible
      • future
        • future
        • std::future类型模板
        • std::promise类型模板
        • std::packaged_task类型模板
        • std::async函数模板
        • 关系
      • atomic
    • 引用
    • 类和对象
    • 友元和运算符重载
    • 继承
    • 继承和多态
    • 模板
    • C++基础总结
    • 类型转换
    • 异常
    • 容器
    • 算法
    • C++程序设计
    • C++ Primer总结
    • 编程技巧
    • 标准库体系结构与内核分析
    • 设计模式
    • cmake配置C++工程
    • libcurl的使用总结
    • web开发框架--drogon
    • log4cplus使用
    • C++数据类型
    • 函数
    • 线程
    • 进程
    • 文件操作
    • 日常问题记录
    • Cpp案例程序
    • 多线程
    • 侯捷c++11新特性
    • 侯捷stl
  • Lua技术栈

  • edoyun

  • 内存管理

  • 数据结构

  • 网络编程

  • Linux

  • 池化技术

  • 操作系统

  • python

  • 编程技术
  • CPlusPlus
Agnes001
2022-07-05

future

https://blog.csdn.net/fengbingchun/article/details/104115489?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-1.pc_relevant_without_ctrlist&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-1.pc_relevant_without_ctrlist&utm_relevant_index=1

# future

头文件提供处理异步结果(在其他线程上执行额结果)的工具。

namespace std
{
  enum class future_status {
      ready, timeout, deferred };

  enum class future_errc
  {
    broken_promise,
    future_already_retrieved,
    promise_already_satisfied,
    no_state
  };

  class future_error;

  const error_category& future_category();

  error_code make_error_code(future_errc e);
  error_condition make_error_condition(future_errc e);

  template<typename ResultType>
  class future;

  template<typename ResultType>
  class shared_future;

  template<typename ResultType>
  class promise;

  template<typename FunctionSignature>
  class packaged_task; // no definition provided

  template<typename ResultType,typename ... Args>
  class packaged_task<ResultType (Args...)>;

  enum class launch {
    async, deferred
  };

  template<typename FunctionType,typename ... Args>
  future<result_of<FunctionType(Args...)>::type> async(FunctionType&& func,Args&& ... args);

  template<typename FunctionType,typename ... Args>
  future<result_of<FunctionType(Args...)>::type> async(std::launch policy,FunctionType&& func,Args&& ... args);
}

# std::future类型模板

future 封装的是一种访问异步操作的机制,我们看看官方文档怎么说说:

The class template std::future provides a mechanism to access the result of asynchronous operations: An asynchronous operation (created via std::async, std::packaged_task, or std::promise) can provide a std::future object to the creator of that asynchronous operation…

当在一个线程(creator)中创建(通过std::async,std::packaged_task 或者 std::promise)了一个异步操作(asynchronous operations,通常就是创建了一个新的线程,执行操作)的时候,这个异步操作会返回一个 future 对象给当前的线程,供其访问异步操作的状态,结果等等。

future 某种意义上表示的是一个异步操作,通过其成员函数我们能够获悉异步操作处于什么样的情况。可以通过 get 来等待异步操作结束并返回结果,是一个阻塞过程。wait 等待异步操作结束结束,也是一个阻塞过程。wait_for 是超时等待返回结果,wait_util 类似。

std::future_status status;
do 
{
    status = future.wait_for(std::chrono::seconds(1));
    if (status == std::future_status::deferred) 
    {
        std::cout << "deferred\n";
    } 
    else if (status == std::future_status::timeout) 
    {
        std::cout << "timeout\n";
    } 
    else if (status == std::future_status::ready) 
    {
        std::cout << "ready!\n";
    }
} 
while (status != std::future_status::ready);

# std::promise类型模板

std::promise类型模板提供设置异步结果的方法,这样其他线程就可以通过std::future实例来索引该结果。 专业的 future 提供商

struct MyData
{
	int value;
	float conf;
};
 
MyData data{0, 0.0f};
 
int main()
{
	std::promise<MyData> dataPromise;
	std::future<MyData> dataFuture = dataPromise.get_future();
 
	std::thread producer(
    [&] (std::promise<MyData> &data) -> void {
      std::this_thread::sleep_for(std::chrono::seconds(1));
      data.set_value({2, 1.0f});
    }, 
    std::ref(dataPromise)
  );
 
	std::thread consumer(
    [&] (std::future<MyData> &data) -> void {
      auto a = data.valid();
      std::cout << a << std::endl;
      auto res = data.get();
      std::cout << res.value << "\t" << res.conf << std::endl;
      auto b = data.valid();
      std::cout << b << std::endl;
    }, 
    std::ref(dataFuture)
  );
 
  producer.join();
  consumer.join();
 
  return 0;
}

# std::packaged_task类型模板

packaged_task 是对一个任务的抽象,我们可以给其传递一个函数来完成其构造。 std::packaged_task包装任何可调用目标(函数、lambda表达式、bind表达式、函数对象)以便它可以被异步调用。它的返回值或抛出的异常被存储于能通过std::future对象访问的共享状态中。简言之,将一个普通的可调用函数对象转换为异步执行的任务。

通过packaged_task包装后,可以通过thread启动或者仿函数形式启动,其执行结果返回值或所抛异常被存储于能通过 std::future 对象访问的共享状态中。

#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <chrono>
#include <future>
using namespace std;
//普通函数
int Add(int x, int y)
{
    return x + y;
}
void task_lambda()
{
    //包装可调用目标时lambda
    packaged_task<int(int,int)> task([](int a, int b){ return a + b;});    
    //仿函数形式,启动任务
    task(2, 10);    
    //获取共享状态中的值,直到ready才能返回结果或者异常
    future<int> result = task.get_future();
    cout << "task_lambda :" << result.get() << "\n";
}
void task_thread()
{
    //包装普通函数
    std::packaged_task<int (int,int)> task(Add);
    future<int> result = task.get_future();
    //启动任务,非异步
    task(4,8);
    cout << "task_thread :" << result.get() << "\n";
        
    //重置共享状态
    task.reset();
    result = task.get_future();

    //通过线程启动任务,异步启动
    thread td(move(task), 2, 10);
    td.join();
    //获取执行结果
    cout << "task_thread :" << result.get() << "\n";
}

int main(int argc, char *argv[])
{
    task_lambda();
    task_thread();
    return 0;
}

# std::async函数模板

std::async 大概的工作过程:先将异步操作用 std::packaged_task 包装起来,然后将异步操作的结果放到 std::promise 中,这个过程就是创造未来的过程。外面再通过 future.get/wait 来获取这个未来的结果。可以说,std::async 帮我们将 std::future、std::promise 和 std::packaged_task 三者结合了起来。

template <class Fn, class... Args>
future<typename result_of<Fn(Args...)>::type>
  async (launch policy, Fn&& fn, Args&&... args);

//该模板函数 async 异步地运行函数 fn 并返回最终将保存该函数调用结果的 std::future 中,其中policy策略有以下三种:
// 异步启动的策略  
enum class launch {  
    // 异步启动,在调用std::async()时创建一个新的线程以异步调用函数,并返回future对象;
    async = 0x1,
    // 延迟启动,在调用std::async()时不创建线程,直到调用了future对象的get()或wait()方法时,才创建线程;                    
    deferred = 0x2,  
     // 自动,函数在某一时刻自动选择策略,这取决于系统和库的实现,通常是优化系统中当前并发的可用性           
    any = async | deferred,      
    sync = deferred  
}; 
// launch::async vs launch::deferred
#include <iostream>     // std::cout
#include <future>       // std::async, std::future, std::launch
#include <chrono>       // std::chrono::milliseconds
#include <thread>       // std::this_thread::sleep_for

void print_ten (char c, int ms) {
  for (int i=0; i<10; ++i) {
    std::this_thread::sleep_for (std::chrono::milliseconds(ms));
    std::cout << c;
  }
}

int main ()
{
  std::cout << "with launch::async:\n";
  std::future<void> foo = std::async (std::launch::async,print_ten,'*',100);
  std::future<void> bar = std::async (std::launch::async,print_ten,'@',200);
  // async "get" (wait for foo and bar to be ready):
  foo.get();
  bar.get();
  std::cout << "\n\n";

  std::cout << "with launch::deferred:\n";
  foo = std::async (std::launch::deferred,print_ten,'*',100);
  bar = std::async (std::launch::deferred,print_ten,'@',200);
  // deferred "get" (perform the actual calls):
  foo.get();
  bar.get();
  std::cout << '\n';

  return 0;
}

# 关系

std::future是用于获取将来共享状态的运行结果或异常,相当于一个中间件,std::async 、std::promise、std::packaged_task都离不开它的帮助;

std::packaged_task用于包装可调用目标,以便异步执行任务;

std::promise用于设置共享状态的值,可以用于线程间交流,这个是比较特殊的。

std::async是最优雅地方式启动任务异步执行;在多数情况下,建议使用asyn开启异步任务,而不是使用packaged_task方式。

编辑此页
condition_varible
atomic

← condition_varible atomic →

Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式