C++11中std::async的使用详解

所属分类: 软件编程 / C 语言 阅读数: 49
收藏 0 赞 0 分享

C++11中的std::async是个模板函数。std::async异步调用函数,在某个时候以Args作为参数(可变长参数)调用Fn,无需等待Fn执行完成就可返回,返回结果是个std::future对象。Fn返回的值可通过std::future对象的get成员函数获取。一旦完成Fn的执行,共享状态将包含Fn返回的值并ready。

std::async有两个版本:

1.无需显示指定启动策略,自动选择,因此启动策略是不确定的,可能是std::launch::async,也可能是std::launch::deferred,或者是两者的任意组合,取决于它们的系统和特定库实现。

2.允许调用者选择特定的启动策略。

std::async的启动策略类型是个枚举类enum class launch,包括:

1. std::launch::async:异步,启动一个新的线程调用Fn,该函数由新线程异步调用,并且将其返回值与共享状态的访问点同步。

2. std::launch::deferred:延迟,在访问共享状态时该函数才被调用。对Fn的调用将推迟到返回的std::future的共享状态被访问时(使用std::future的wait或get函数)。

参数Fn:可以为函数指针、成员指针、任何类型的可移动构造的函数对象(即类定义了operator()的对象)。Fn的返回值或异常存储在共享状态中以供异步的std::future对象检索。

参数Args:传递给Fn调用的参数,它们的类型应是可移动构造的。

返回值:当Fn执行结束时,共享状态的std::future对象准备就绪。std::future的成员函数get检索的值是Fn返回的值。当启动策略采用std::launch::async时,即使从不访问其共享状态,返回的std::future也会链接到被创建线程的末尾。在这种情况下,std::future的析构函数与Fn的返回同步。

std::future介绍参考:https://www.jb51.net/article/179229.htm

详细用法见下面的测试代码,下面是从其他文章中copy的测试代码,部分作了调整,详细内容介绍可以参考对应的reference:

#include "future.hpp"
#include <iostream>
#include <future>
#include <chrono>
#include <utility>
#include <thread>
#include <functional>
#include <memory>
#include <exception> 
#include <numeric>
#include <vector>
#include <cmath>
#include <string>
#include <mutex>
 
namespace future_ {
 
///////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/future/async/
int test_async_1()
{
 auto is_prime = [](int x) {
 std::cout << "Calculating. Please, wait...\n";
 for (int i = 2; i < x; ++i) if (x%i == 0) return false;
 return true;
 };
 
 // call is_prime(313222313) asynchronously:
 std::future<bool> fut = std::async(is_prime, 313222313);
 
 std::cout << "Checking whether 313222313 is prime.\n";
 // ...
 
 bool ret = fut.get(); // waits for is_prime to return
 if (ret) std::cout << "It is prime!\n";
 else std::cout << "It is not prime.\n";
 
 return 0;
}
 
///////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/future/launch/
int test_async_2()
{
 auto 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;
 }
 };
 
 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;
}
 
///////////////////////////////////////////////////////////
// reference: https://en.cppreference.com/w/cpp/thread/async
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)
{
 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 test_async_3()
{
 std::vector<int> v(10000, 1);
 std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n';
 
 X x;
 // Calls (&x)->foo(42, "Hello") with default policy:
 // may print "Hello 42" concurrently or defer execution
 auto a1 = std::async(&X::foo, &x, 42, "Hello");
 // Calls x.bar("world!") with deferred policy
 // prints "world!" when a2.get() or a2.wait() is called
 auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");
 // Calls X()(43); with async policy
 // prints "43" concurrently
 auto a3 = std::async(std::launch::async, X(), 43);
 a2.wait();           // prints "world!"
 std::cout << a3.get() << '\n'; // prints "53"
 
 return 0;
} // if a1 is not done at this point, destructor of a1 prints "Hello 42" here
 
///////////////////////////////////////////////////////////
// reference: https://thispointer.com/c11-multithreading-part-9-stdasync-tutorial-example/
int test_async_4()
{
 using namespace std::chrono;
 
 auto fetchDataFromDB = [](std::string recvdData) {
 // Make sure that function takes 5 seconds to complete
 std::this_thread::sleep_for(seconds(5));
 //Do stuff like creating DB Connection and fetching Data
 return "DB_" + recvdData;
 };
 
 auto fetchDataFromFile = [](std::string recvdData) {
 // Make sure that function takes 5 seconds to complete
 std::this_thread::sleep_for(seconds(5));
 //Do stuff like fetching Data File
 return "File_" + recvdData;
 };
 
 // Get Start Time
 system_clock::time_point start = system_clock::now();
 
 std::future<std::string> resultFromDB = std::async(std::launch::async, fetchDataFromDB, "Data");
 
 //Fetch Data from File
 std::string fileData = fetchDataFromFile("Data");
 
 //Fetch Data from DB
 // Will block till data is available in future<std::string> object.
 std::string dbData = resultFromDB.get();
 
 // Get End Time
 auto end = system_clock::now();
 auto diff = duration_cast <std::chrono::seconds> (end - start).count();
 std::cout << "Total Time Taken = " << diff << " Seconds" << std::endl;
 
 //Combine The Data
 std::string data = dbData + " :: " + fileData;
 //Printing the combined Data
 std::cout << "Data = " << data << std::endl;
 
 return 0;
}
 
} // namespace future_

GitHub:https://github.com/fengbingchun/Messy_Test

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

C语言数组入门之数组的声明与二维数组的模拟

这篇文章主要介绍了C语言数组入门之数组的声明与二维数组的模拟,数组学习的同时也要相应理解C语言指针的作用,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言中变量与其内存地址对应的入门知识简单讲解

这篇文章主要介绍了C语言中变量与其内存地址对应的入门知识简单讲解,同时这也是掌握指针部分知识的基础,需要的朋友可以参考下
收藏 0 赞 0 分享

讲解C语言编程中指针赋值的入门实例

这篇文章主要介绍了讲解C语言编程中指针赋值的入门实例,通过const int i与int *const pi这样两个例子来分析指针的赋值和地址指向,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言中的结构体的入门学习教程

这篇文章主要介绍了C语言中的结构体的入门学习教程,以struct语句定义的结构体是C语言编程中的重要基础,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言编程入门之程序头文件的简要解析

这篇文章主要介绍了C语言编程入门之程序头文件的简要解析,包括头文件重复包含问题等方面的说明,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言编程中的联合体union入门学习教程

这篇文章主要介绍了C语言编程中的联合体union入门学习教程,也是C语言入门学习中的基础知识,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言中数组作为函数的参数以及返回值的使用简单入门

这篇文章主要介绍了C语言中数组作为函数的参数以及返回值的使用简单入门,这里以一维数组作为基本条件进行例子讲解,需要的朋友可以参考下
收藏 0 赞 0 分享

MySQL的内存表的基础学习教程

这篇文章主要介绍了MySQL的内存表的基础学习教程,包括内存表的创建以及使用限制等等,需要的朋友可以参考下
收藏 0 赞 0 分享

C++中头文件的概念与基本编写方法

这篇文章主要介绍了C++中头文件的概念与基本编写方法,是C++入门学习中的基础知识,需要的朋友可以参考下
收藏 0 赞 0 分享

jQuery移动页面开发中主题按钮的设计示例

这篇文章主要介绍了jQuery移动页面开发中主题按钮的设计示例,jQuery是当今最具人气的JavaScript开发类库,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多