C++异步的使用场景:一个线程需要获取其他线程中的值。
麻烦但直接做法,定义一个全局变量,然后用条件变量进行同步。
C++11提供了更简洁的方法实现。
std::future
作用
future的作用是阻塞调用线程,直到工作线程获得所需要的值或异常
特性
- 不能拷贝,只能移动
- 所存储的可能是异常
- API
get()
阻塞该函数直到获得相应的值wait()
阻塞直到结果就绪wait_for()
等待一段时间,返回future_status(见下)wait_until()
等待到一个时间点,返回future_statusvalid()
检查未来提是否拥有共享状态
- future_status
future_status
(枚举值)为wait_for()
或者wait_until()
的返回值,有三种状态
enum class future_status {
ready,//状态就绪
timeout,//时间耗尽也为就绪
deferrd//函数被推迟执行
};
promise
用法
从调用get_future()
方法获取future
对象,再将promise
通过引用、指针或右值引用等方法将promise
传递到另一个线程,在对promise
对象调用set_value()
等方法传回主线程所期待的值。promise
只能使用一次
API
get_future()
返回与promise
关联的future
set_value()
设置结果为指定值set_value_at_thread_exit()
设置结果为指定值,子线程资源被销毁后数据才就绪set_exception()
设置结果为指示异常set_exception_at_thread_exit()
示例
代码来源
#include <chrono>
#include <future>
#include <iostream>
#include <numeric>
#include <thread>
#include <vector>
void accumulate(std::vector<int>::iterator first,
std::vector<int>::iterator last,
std::promise<int> accumulate_promise)
{
int sum = std::accumulate(first, last, 0);
accumulate_promise.set_value(sum); // 提醒 future
}
void do_work(std::promise<void> barrier)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
barrier.set_value();
}
int main()
{
// 演示用 promise<int> 在线程间传递结果。
std::vector<int> numbers = {1, 2, 3, 4, 5, 6};
std::promise<int> accumulate_promise;
//获得与promise关联的future
std::future<int> accumulate_future = accumulate_promise.get_future();
//右值引用的方式将std::promise对象传递到子线程中区
std::thread work_thread(accumulate, numbers.begin(), numbers.end(),
std::move(accumulate_promise));
// future::get() 将等待直至该 future 拥有合法结果并取得它
// 无需在 get() 前调用 wait()
// accumulate_future.wait(); // 等待结果
std::cout << "result=" << accumulate_future.get() << '\n';
work_thread.join(); // wait for thread completion
// 演示用 promise<void> 在线程间对状态发信号
std::promise<void> barrier;
std::future<void> barrier_future = barrier.get_future();
std::thread new_work_thread(do_work, std::move(barrier));
barrier_future.wait();
new_work_thread.join();
}
packaged_task
用法:
包装一个可调用对象,将其返回值或异常储存在与其相关联的future中
API:
get_future()
返回关联的future对象operator()
调用包装的可执行对象make_ready_at_thread_exit()
线程退出后使future就绪reset()
重置状态
#include <cmath>
#include <functional>
#include <future>
#include <iostream>
#include <thread>
// 避免对 std::pow 重载集消歧义的独有函数
int f(int x, int y) { return std::pow(x,y); }
void task_lambda()
{
std::packaged_task<int(int, int)> task([](int a, int b)
{
return std::pow(a, b);
});
std::future<int> result = task.get_future();
task(2, 9);
std::cout << "task_lambda:\t" << result.get() << '\n';
}
void task_bind()
{
std::packaged_task<int()> task(std::bind(f, 2, 11));
std::future<int> result = task.get_future();
task();
std::cout << "task_bind:\t" << result.get() << '\n';
}
void task_thread()
{
std::packaged_task<int(int, int)> task(f);
std::future<int> result = task.get_future();
std::thread task_td(std::move(task), 2, 10);
task_td.join();
std::cout << "task_thread:\t" << result.get() << '\n';
}
int main()
{
task_lambda();
task_bind();
task_thread();
}
async
用法
异步运行一个函数,将返回值储存在与之关联的future中。函数可能在一个新线程中执行,也可能在原线程中执行
template< class F, class... Args >
async( F&& f, Args&&... args );
template< class F, class... Args >
async( std::launch policy, F&& f, Args&&... args );
返回一个与之关联的future对象
启动策略—launch
async函数第一个参数可为launch
launch是
enum class launch : {
async,
deferred,
};
launch::async
表示为创建一个新的线程异步执行任务
launch::deferred
表示直到相关联的future调用get()或wait()等函数才执行,不创建新线程
如果不指定调度策略,则由标准库的调度器决定由哪种方式执行,
相当于std::launch::async | std::launch::deferred
代码来源
#include <algorithm>
#include <future>
#include <iostream>
#include <mutex>
#include <numeric>
#include <string>
#include <vector>
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 main()
{
std::vector<int> v(10000, 1);
std::cout << "和为 " << parallel_sum(v.begin(), v.end()) << '\n';
X x;
// 以默认策略调用 x.foo(42, "Hello") :
// 可能同时打印 "Hello 42" 或延迟执行
auto a1 = std::async(&X::foo, &x, 42, "Hello");
// 以 deferred 策略调用 x.bar("world!")
// 调用 a2.get() 或 a2.wait() 时打印 "world!"
auto a2 = std::async(std::launch::deferred, &X::bar, x, "world!");
// 以 async 策略调用 X()(43) :
// 同时打印 "43"
auto a3 = std::async(std::launch::async, X(), 43);
a2.wait(); // 打印 "world!"
std::cout << a3.get() << '\n'; // 打印 "53"
} // 若 a1 在此点未完成,则 a1 的析构函数在此打印 "Hello 42"