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

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介绍参考:C++11中std::future的具体使用方法_C 语言_脚本之家

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

#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):
		bar.get();
		foo.get(); // 注:注释掉此句,则不会输出'**********'
		
		std::cout << '\n';

		return 0;
	}

	///
	// reference: https://en.cppreference.com/w/cpp/thread/async
	std::mutex m;

	struct X {
		int testxx;
		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;
		x.testxx = 8;
		// 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);

		std::this_thread::sleep_for(std::chrono::seconds(2));
		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_

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
是的,C++ 11 引入了 std::async 函数,可以用它来创建异步任务。std::async 函数的原型如下所示: ```c++ template <class Function, class... Args> std::future<typename std::result_of<Function(Args...)>::type> async(Function&& f, Args&&... args); ``` std::async 函数的作用是创建一个异步任务,并返回一个 std::future 对象,用于获取异步任务的返回值。std::async 函数的第一个参数是要执行的函数,后面的参数是该函数的参数。该函数会在一个新线程执行,并在执行完成后返回结果。如果该函数抛出异常,则 std::future 对象会保存该异常信息。 std::async 函数还可以指定执行策略,例如 std::launch::async 表示在新线程执行异步任务,std::launch::deferred 表示在调用 std::future::get() 函数时执行异步任务。如果不指定执行策略,则由编译器自行决定。 以下是一个使用 std::async 函数创建异步任务的示例: ```c++ #include <iostream> #include <future> int foo(int x) { std::cout << "foo is running in thread " << std::this_thread::get_id() << std::endl; return x + 1; } int main() { std::future<int> result = std::async(std::launch::async, foo, 1); std::cout << "main is running in thread " << std::this_thread::get_id() << std::endl; std::cout << "result is " << result.get() << std::endl; return 0; } ``` 在上面的示例使用 std::async 函数创建了一个异步任务 foo,并将参数 1 传递给该函数。执行结果会保存在 std::future 对象,可以使用 std::future::get() 函数获取异步任务的返回值。在主线程也输出了一些信息,用于对比异步任务和主线程的执行情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值