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 实例引用所有给定的异步结果。
定义于头文件 | ||
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::async 、 std::packaged_task 或 std::promise 创建的)异步操作能提供一个
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 将返回异步任务的值或异常(如果发生了异常)。
成员函数
从 *this 转移共享状态给 shared_future 并返回它(公开成员函数) | |
获取结果 | |
返回结果 (公开成员函数) | |
状态 | |
检查 future 是否拥有共享状态 (公开成员函数) | |
等待结果变得可用 (公开成员函数) | |
等待结果,如果在指定的超时间隔后仍然无法得到结果,则返回。 (公开成员函数) | |
等待结果,如果在已经到达指定的时间点时仍然无法得到结果,则返回。 (公开成员函数) |
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::ready | 0 | wait_for(或wait_until) 因为共享状态的标志变为 ready 而返回。 |
future_status::timeout | 1 | 超时,即 wait_for(或wait_until) 因为在指定的时间段(或时刻)内共享状态的标志依然没有变为 ready 而返回。 |
future_status::deferred | 2 | 共享状态包含了 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.
成员函数
获取结果 | |
返回结果 (公开成员函数) | |
状态 | |
检查 future 是否拥有共享状态 (公开成员函数) | |
等待结果变得可用 (公开成员函数) | |
等待结果,如果在指定的超时间隔后仍然无法得到结果,则返回。 (公开成员函数) | |
等待结果,如果在已经到达指定的时间点时仍然无法得到结果,则返回。 (公开成员函数) |
类模板 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");
}
以上参考:
- https://www.cnblogs.com/chenny7/p/11996237.html
- https://www.cnblogs.com/haippy/p/3280643.html
- https://zh.cppreference.com/w/cpp/thread
- C++并发编程实战