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

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

定义于头文件 <future>
异步运行一个函数(有可能在新线程中执行),并返回保有其结果的 std::future
(1)
template< class Function, class... Args>
std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
async( Function&& f, Args&&... args );  (C++11 起)  (C++17 前) 

template< class Function, class... Args> 
std::future<std::invoke_result_t<std::decay_t<Function>,std::decay_t<Args>...>>
async( Function&& f, Args&&... args );  (C++17 起)  (C++20 前) 

template< class Function, class... Args>
[[nodiscard]] std::future<std::invoke_result_t<std::decay_t<Function>,
std::decay_t<Args>...>> async( Function&& f, Args&&... args );  (C++20 起) 


 (2)  
template< class Function, class... Args >
std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
async( std::launch policy, Function&& f, Args&&... args );  (C++11 起)(C++17 前) 

template< class Function, class... Args > 
std::future<std::invoke_result_t<std::decay_t<Function>,std::decay_t<Args>...>>
async( std::launch policy, Function&& f, Args&&... args );  (C++17 起)(C++20 前) 

template< class Function, class... Args >
[[nodiscard]]std::future<std::invoke_result_t<std::decay_t<Function>,
std::decay_t<Args>...>>async( 
std::launch policy, Function&& f, Args&&... args );  (C++20 起) 

模板函数 async 异步地运行函数 f (潜在地在可能是线程池一部分的分离线程中),并返回最终将保有该函数调用结果的 std::future 。

1) 表现如同以 policy 为 std::launch::async | std::launch::deferred 调用 (2) 。换言之, f 可能执行于另一线程,或者它可能在查询产生的 std::future 的值时同步运行。

2) 按照特定的执行策略 policy ,以参数 args 调用函数 f

  • 若设置 async 标志(即 (policy & std::launch::async) != 0 ),则 async 在新的执行线程(初始化所有线程局域对象后)执行可调用对象 f ,如同产出 std::thread(std::forward<F>(f), std::forward<Args>(args)...) ,除了若 f 返回值或抛出异常,则于可通过 async 返回给调用方的 std::future 访问的共享状态存储结果。
  • 若设置 deferred 标志(即 (policy & std::launch::deferred) != 0 ),则 async 以同 std::thread 构造函数的方式转换 fargs... ,但不产出新的执行线程。而是进行惰性求值:在 async 所返回的 std::future 上首次调用非定时等待函数,将导致在当前线程(不必是最初调用 std::async 的线程)中,以 args... (作为右值传递)的副本调用 f (亦作为右值)的副本。将结果或异常置于关联到该 future 的共享状态,然后才令它就绪。对同一 std::future 的所有后续访问都会立即返回结果。
  • policy 中设置了 std::launch::async 和 std::launch::deferred 两个标志,则进行异步执行还是惰性求值取决于实现。
  • policy 中未设置 std::launch::async 或 std::launch::deferred 或任何实现定义策略标志,则行为未定义。
(C++14 起)

任何情况下,对 std::async 的调用同步于(定义于 std::memory_order )对 f 的调用,且 f 的完成先序于令共享状态就绪。若选择 async 策略,则关联线程的完成同步于首个等待于共享状态上的函数的成功返回,或最后一个释放共享状态的函数的返回,两者的先到来者。

参数

f-要调用的可调用 (Callable) 对象
args...-传递给 f 的参数
policy-位掩码值,每个单独位控制允许的执行方法
解释
std::launch::async启用异步求值
std::launch::deferred启用惰性求值

类型要求
- Function, Args 必须满足可移动构造 (MoveConstructible) 的要求。

返回值

指代此次调用 std::async 所创建的共享状态的 std::future 。

异常

若运行策略等于 std::launch::async 且实现无法开始新线程(该情况下,若运行策略为 async|deferred 或设置了额外位,则它将回退到 deferred 或实现定义的策略),则抛出以 std::errc::resource_unavailable_try_again 为错误条件的 std::system_error ,或者若无法分配内部数据结构所用的内存,则为 std::bad_alloc 。

注意

实现可以通过在默认运行策略中启用额外(实现定义的)位,扩展 std::async 第一重载的行为。

实现定义的运行策略的例子是同步策略(在 async 调用内立即执行)和任务策略(类似 async ,但不清理线程局域对象)。

若从 std::async 获得的 std::future 未被移动或绑定到引用,则在完整表达式结尾, std::future 的析构函数将阻塞直至异步计算完成,实质上令如下代码同步:

std::async(std::launch::async, []{ f(); }); // 临时量的析构函数等待 f()
std::async(std::launch::async, []{ g(); }); // f() 完成前不开始

(注意,以调用 std::async 以外的方式获得的 std::future 的析构函数决不阻塞)

调用示例

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <future>
#include <string>
#include <mutex>

int  count(0);
std::mutex mPrint;
void printThis_thread(const std::thread::id &id)
{
    std::unique_lock<std::mutex> lock(mPrint);
    count++;
    std::cout << "this_thread: " << id << "     count:" << count << std::endl;
}

std::mutex m;
struct X
{
    void foo(int i, const std::string& str)
    {
        std::lock_guard<std::mutex> lk(m);
        std::cout << str << ' ' << i << '\n';
    }
    void bar(const std::string& str)
    {
        std::lock_guard<std::mutex> lk(m);
        std::cout << str << '\n';
    }
    int operator()(int i)
    {
        std::lock_guard<std::mutex> lk(m);
        std::cout << i << '\n';
        return i + 10;
    }
};

template <typename RandomIt>
int parallel_sum(RandomIt beg, RandomIt end)
{
    printThis_thread(std::this_thread::get_id());
    auto len = end - beg;
    if (len < 1000)
    {
        return std::accumulate(beg, end, 0);
    }

    RandomIt mid = beg + len / 2;
    auto handle = std::async(std::launch::async,
                             parallel_sum<RandomIt>, mid, end);
    int sum = parallel_sum(beg, mid);
    return sum + handle.get();
}

int main()
{
    std::vector<int> v(10000, 1);
    std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n';

    X x;
    // 以默认策略调用 x.foo(42, "Hello") :
    // 可能同时打印 "Hello 42" 或延迟执行
    auto a1 = std::async(&X::foo, &x, 42, "Hello");
    // 以 deferred 策略调用 x.bar("world!")
    // 调用 a2.get() 或 a2.wait() 时打印 "world!"
    auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");
    // 以 async 策略调用 X()(43) :
    // 同时打印 "43"
    auto a3 = std::async(std::launch::async, X(), 43);
    a2.wait();                     // 打印 "world!"
    std::cout << a3.get() << '\n'; // 打印 "53"
} // 若 a1 在此点未完成,则 a1 的析构函数在此打印 "Hello 42"

输出

 

相关文章:

  • 修复 JavaScript 错误的四种方法
  • 基本的Python内置函数
  • WANem弱网环境模拟工具的使用探索
  • springboot毕设项目医院预约挂号系统ey211(java+VUE+Mybatis+Maven+Mysql)
  • 深入理解计算机系统,汇编的流程控制
  • 202206-2 CCF 寻宝!大冒险! (简单模拟 满分题解)
  • Linux 下基于cpr 开发 http 应用 : 通过编译安装cpr源码方式进行C++ 开发
  • Android初级工程师进阶教程
  • 【Python零基础入门篇 · 3】:掌握数值类型、进制的转换
  • 基于ssm的电动车实名制挂牌管理系统
  • 解锁新技能《Redis ACL SETUSER命令》
  • 1044 Shopping in Mars(二分)
  • 最大公约数——Hankson的趣味题(线筛法求质数+gcd+质因数组合搜索约数)
  • 华为云弹性云服务器有哪些优势?
  • word图片无法居中,原因可能是非嵌入式!
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • CentOS 7 修改主机名
  • DataBase in Android
  • Debian下无root权限使用Python访问Oracle
  • ECMAScript6(0):ES6简明参考手册
  • gitlab-ci配置详解(一)
  • JavaScript 奇技淫巧
  • jdbc就是这么简单
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • nfs客户端进程变D,延伸linux的lock
  • Redis 中的布隆过滤器
  • 半理解系列--Promise的进化史
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 机器学习学习笔记一
  • 基于web的全景—— Pannellum小试
  • 容器服务kubernetes弹性伸缩高级用法
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 数据仓库的几种建模方法
  • 一个JAVA程序员成长之路分享
  • 鱼骨图 - 如何绘制?
  • 走向全栈之MongoDB的使用
  • ionic入门之数据绑定显示-1
  • #单片机(TB6600驱动42步进电机)
  • $.ajax()
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (pytorch进阶之路)扩散概率模型
  • (二)斐波那契Fabonacci函数
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (一)80c52学习之旅-起始篇
  • (一)kafka实战——kafka源码编译启动
  • (转)AS3正则:元子符,元序列,标志,数量表达符
  • (转)memcache、redis缓存
  • .NET 3.0 Framework已经被添加到WindowUpdate
  • .NET CF命令行调试器MDbg入门(四) Attaching to Processes