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


    定义于头文件 
    异步运行一个函数(有可能在新线程中执行),并返回保有其结果的 std::future
    1. 1
    2. template< class Function, class... Args>
    3. std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
    4. async( Function&& f, Args&&... args ); (C++11 起) (C++17 前)
    5. template< class Function, class... Args>
    6. std::future<std::invoke_result_t<std::decay_t<Function>,std::decay_t<Args>...>>
    7. async( Function&& f, Args&&... args ); (C++17 起) (C++20 前)
    8. template< class Function, class... Args>
    9. [[nodiscard]] std::future<std::invoke_result_t<std::decay_t<Function>,
    10. std::decay_t<Args>...>> async( Function&& f, Args&&... args ); (C++20 起)
    11. (2)
    12. template< class Function, class... Args >
    13. std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
    14. async( std::launch policy, Function&& f, Args&&... args ); (C++11 起)(C++17 前)
    15. template< class Function, class... Args >
    16. std::future<std::invoke_result_t<std::decay_t<Function>,std::decay_t<Args>...>>
    17. async( std::launch policy, Function&& f, Args&&... args ); (C++17 起)(C++20 前)
    18. template< class Function, class... Args >
    19. [[nodiscard]]std::future<std::invoke_result_t<std::decay_t<Function>,
    20. std::decay_t<Args>...>>async(
    21. 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), std::forward(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 的析构函数决不阻塞)

    调用示例

    1. #include <iostream>
    2. #include <vector>
    3. #include <algorithm>
    4. #include <numeric>
    5. #include <future>
    6. #include <string>
    7. #include <mutex>
    8. int count(0);
    9. std::mutex mPrint;
    10. void printThis_thread(const std::thread::id &id)
    11. {
    12. std::unique_lock<std::mutex> lock(mPrint);
    13. count++;
    14. std::cout << "this_thread: " << id << " count:" << count << std::endl;
    15. }
    16. std::mutex m;
    17. struct X
    18. {
    19. void foo(int i, const std::string& str)
    20. {
    21. std::lock_guard<std::mutex> lk(m);
    22. std::cout << str << ' ' << i << '\n';
    23. }
    24. void bar(const std::string& str)
    25. {
    26. std::lock_guard<std::mutex> lk(m);
    27. std::cout << str << '\n';
    28. }
    29. int operator()(int i)
    30. {
    31. std::lock_guard<std::mutex> lk(m);
    32. std::cout << i << '\n';
    33. return i + 10;
    34. }
    35. };
    36. template <typename RandomIt>
    37. int parallel_sum(RandomIt beg, RandomIt end)
    38. {
    39. printThis_thread(std::this_thread::get_id());
    40. auto len = end - beg;
    41. if (len < 1000)
    42. {
    43. return std::accumulate(beg, end, 0);
    44. }
    45. RandomIt mid = beg + len / 2;
    46. auto handle = std::async(std::launch::async,
    47. parallel_sum<RandomIt>, mid, end);
    48. int sum = parallel_sum(beg, mid);
    49. return sum + handle.get();
    50. }
    51. int main()
    52. {
    53. std::vector<int> v(10000, 1);
    54. std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n';
    55. X x;
    56. // 以默认策略调用 x.foo(42, "Hello") :
    57. // 可能同时打印 "Hello 42" 或延迟执行
    58. auto a1 = std::async(&X::foo, &x, 42, "Hello");
    59. // 以 deferred 策略调用 x.bar("world!")
    60. // 调用 a2.get() 或 a2.wait() 时打印 "world!"
    61. auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");
    62. // 以 async 策略调用 X()(43)
    63. // 同时打印 "43"
    64. auto a3 = std::async(std::launch::async, X(), 43);
    65. a2.wait(); // 打印 "world!"
    66. std::cout << a3.get() << '\n'; // 打印 "53"
    67. } // 若 a1 在此点未完成,则 a1 的析构函数在此打印 "Hello 42"

    输出

     

  • 相关阅读:
    MSQL系列(五) Mysql实战-索引最左侧匹配原则分析及实战
    二十三种设计模式全面解析-单例设计模式:解密全局独一无二的实例创造者
    CubeFS - 新一代云原生存储系统
    中文人物关系知识图谱(含码源):中文人物关系图谱构建、数据回标、基于远程监督人物关系抽取、知识问答等应用.
    盒子阴影(重点)
    【数据库04】中级开发需要掌握哪些SQL进阶玩法
    Java项目:ssm在线视频教育网站
    C++:VS2019 Windows SDK 10损坏重装
    try-catch-finally | 里面有return语句时执行顺序
    经典论文-MobileNetV3论文及实践
  • 原文地址:https://blog.csdn.net/qq_40788199/article/details/126673857