C++2.0——多线程的使用async与future

std::async

async是一种利用现成的硬件并发来运行自包含异步任务的简单途径;对于async的调用返回一个包含任务结果的future;取决于启动的策略,该任务可以异步的运行在它自己的线程上,也可以同步第运行于任何在此future调用的wait或者get成员的线程上。

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 );

std::async中的第一个参数是启动策略,它控制std::async的异步行为,我们可以用三种不同的启动策略来创建std::async:

  • ·std::launch::async: 保证异步行为,即传递函数将在单独的线程中执行
  • ·std::launch::deferred:当其他线程调用get()来访问共享状态时,将调用非异步行为
  • ·std::launch::async | std::launch::deferred:默认行为。有了这个启动策略,它可以异步运行或不运行,这取决于系统的负载,但我们无法控制它。
#include <iostream>
#include <thread>
#include <future>
#include <algorithm>
#include <numeric>

using namespace std;

std::mutex m;
struct X {
	void foo(int i, const std::string& str) {
		std::lock_guard<std::mutex> lk(m);
		std::cout << str.c_str() << ' ' << i << '\n';
	}
	void bar(const std::string& str) {
		std::lock_guard<std::mutex> lk(m);
		std::cout << str.c_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 main()
{

	vector<int> v(10000, 1);

	cout << "The sum is: " << parallel_sum(v.begin(), v.end());

	X x;

	auto a1 = async(&X::foo,&x,43,"hello");//默认的策略,可能在另外的线程,也可能在本线程

	auto a2 = async(launch::deferred,&X::bar,&x,"world");

	chrono::seconds s(2);
	this_thread::sleep_for(s);

	a2.wait();//休眠2s之后打印出world

	auto a3 = async(launch::async,X(),43355);

	this_thread::sleep_for(chrono::seconds(2));

	cout << " a3 result: " << a3.get() << endl;;

	return system("pause");
}

std::future

future类模板提供了从另一个线程等待异步结果的方法,与std::promise、std::packaged_task 类模板和 std::async函数模板联合使用,可以用来提供异步结果;在任意的时刻,只有一个std::future 实例引用所有给定的异步结果。

定义于头文件 <future>

  

template< class T > class future;

(1)(C++11 起)

template< class T > class future<T&>;

(2)(C++11 起)

template<>          class future<void>;

(3)(C++11 起)
   

类模板 std::future 提供访问异步操作结果的机制:

  • 然后,异步操作的创建者能用各种方法查询、等待或从 std::future 提取值。若异步操作仍未提供值,则这些方法可能阻塞。
  • 异步操作准备好发送结果给创建者时,它能通过修改链接到创建者的 std::future 的共享状态(例如 std::promise::set_value )进行。

注意, std::future 所引用的共享状态不与另一异步返回对象共享(与 std::shared_future 相反)。

一个 std::future 对象只有在有效(valid)的情况下才有用(useful),由 std::future 默认构造函数创建的 future 对象不是有效的(除非当前非有效的 future 对象被 move 赋值另一个有效的 future 对象)。

 在一个有效的 future 对象上调用 get 会阻塞当前的调用者,直到 Provider 设置了共享状态的值或异常(此时共享状态的标志变为 ready),std::future::get 将返回异步任务的值或异常(如果发生了异常)。

成员函数

share

从 *this 转移共享状态给 shared_future 并返回它
(公开成员函数)

获取结果

get

返回结果
(公开成员函数)

状态

valid

检查 future 是否拥有共享状态
(公开成员函数)

wait

等待结果变得可用
(公开成员函数)

wait_for

等待结果,如果在指定的超时间隔后仍然无法得到结果,则返回。
(公开成员函数)

wait_until

等待结果,如果在已经到达指定的时间点时仍然无法得到结果,则返回。
(公开成员函数)

1. share 与 valid

转移 *this 的共享状态,若存在,到 std::shared_future 对象。多个 std::shared_future 对象可引用同一共享对象,这对于 std::future 不可能;在 std::future 上调用 share 后 valid() == false 。

#include <iostream>
#include <thread>
#include <future>
#include <chrono>
using namespace std;

int add(int x, int y)
{
	return x + y;
}

int main() 
{
	future<int> fut = async(add,5,13);

	cout << " before share:  " << fut.valid() << endl;

	shared_future<int> share_fut = fut.share();

	cout << "  after share: " << fut.valid() << endl;

	return system("pause");
}

输出结果:

2. wait_for

int main()
{
    std::future<int> future = std::async(std::launch::async, [](){ 
        std::this_thread::sleep_for(std::chrono::seconds(3));
        return 8;  
    }); 
 
    std::cout << "waiting...\n";
    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::cout << "result is " << future.get() << '\n';
}

3. std::future_status 类型

std::future_status 类型主要用在 std::future(或std::shared_future)中的 wait_for 和 wait_until 两个函数中的。

类型取值描述
future_status::ready0wait_for(或wait_until) 因为共享状态的标志变为 ready 而返回。
future_status::timeout1超时,即 wait_for(或wait_until) 因为在指定的时间段(或时刻)内共享状态的标志依然没有变为 ready 而返回。
future_status::deferred2共享状态包含了 deferred 函数。

std::shared_future

std::shared_future 与 std::future 类似,但是 std::shared_future 可以拷贝、多个 std::shared_future 可以共享某个共享状态的最终结果(即共享状态的某个值或者异常)。shared_future 可以通过某个 std::future 对象隐式转换(参见 std::shared_future 的构造函数),或者通过 std::future::share() 显示转换,无论哪种转换,被转换的那个 std::future 对象都会变为 not-valid.

成员函数

获取结果

get

返回结果
(公开成员函数)

状态

valid

检查 future 是否拥有共享状态
(公开成员函数)

wait

等待结果变得可用
(公开成员函数)

wait_for

等待结果,如果在指定的超时间隔后仍然无法得到结果,则返回。
(公开成员函数)

wait_until

等待结果,如果在已经到达指定的时间点时仍然无法得到结果,则返回。
(公开成员函数)

类模板 std::shared_future 提供访问异步操作结果的机制,类似 std::future ,除了允许多个线程等候同一共享状态。不同于仅可移动的 std::future (故只有一个实例能指代任何特定的异步结果),std::shared_future 可复制而且多个 shared_future 对象能指代同一共享状态。若每个线程通过其自身的 shared_future 对象副本访问,则从多个线程访问同一共享状态是安全的。

#include <iostream>
#include <thread>
#include <future>
#include <mutex>
using namespace std;


int main() 
{
	promise<void> ready_promise, t1_ready_promise, t2_ready_promise;
	shared_future<void> ready_future(ready_promise.get_future());

	std::chrono::time_point<std::chrono::high_resolution_clock> start;

	auto fun1 = [&, ready_future]()->chrono::duration<double, milli> 
	{
		t1_ready_promise.set_value();
		ready_future.wait();
		return chrono::high_resolution_clock::now() - start;
	};

	auto fun2 = [&, ready_future]() -> std::chrono::duration<double, std::milli>
	{
		t2_ready_promise.set_value();
		ready_future.wait(); // 等待来自 main() 的信号
		return std::chrono::high_resolution_clock::now() - start;
	};

	auto result1 = std::async(std::launch::async, fun1);//异步任务fun1
	auto result2 = std::async(std::launch::async, fun2);//异步任务fun2

	// 等待线程变为就绪
	t1_ready_promise.get_future().wait();
	t2_ready_promise.get_future().wait();


	// 线程已就绪,开始时钟
	start = std::chrono::high_resolution_clock::now();

	// 异步任务fun1、fun2在等待,向线程发信使之运行
	ready_promise.set_value();

	std::cout << "Thread 1 received the signal "
		<< result1.get().count() << " ms after start\n"
		<< "Thread 2 received the signal "
		<< result2.get().count() << " ms after start\n";



	return system("pause");
}

 

以上参考:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值