C++11提供了异步操作相关的类,主要有std::future,std::promise和std::package_task.
1.获取线程函数返回值的类std::future
future有三种状态:
- Defered,异步操作还没有开始
- Ready,异步操作已经完成
- Timeout,异步操作超时
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
void task(int a, int b, std::promise<int>& ret)
{
int ret_a = a * a;
int ret_b = b * 2;
std::this_thread::sleep_for(std::chrono::seconds(3));
ret.set_value(ret_b + ret_a);
}
int main()
{
std::promise<int> p;
std::future<int> f = p.get_future();//将二者联系起来
std::thread t(task, 1, 2, std::ref(p));//将它作为一个参数传递给子线程
std::cout << "return value is:" << f.get();//获取计算的结果
t.join();
return 0;
}
注意: future.get()操作只能进行一次,多次会崩溃
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
//用法二 延迟传参
void task(int a, std::future<int>& b, std::promise<int>& ret)
{
int ret_a = a * a;
std::this_thread::sleep_for(std::chrono::seconds(3));
int ret_b = b.get() * 2;
ret.set_value(ret_b + ret_a);
}
int main()
{
std::promise<int> p;
std::future<int> f = p.get_future();//将二者联系起来
std::thread t(task, 1, std::ref(f), std::ref(p));
p.set_value(4);
std::cout << "f:get->" << f.get() << std::endl;
t.join();
return 0;
}
std::shared_future可以多次get操作,可以通过future的shared操作获取
2. async异步获取操作
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
//用法二 延迟传参
int task(int a, int b)
{
int ret_a = a * a;
std::this_thread::sleep_for(std::chrono::seconds(3));
int ret_b = b * 2;
std::cout << std::this_thread::get_id() << std::endl;
return ret_a + ret_b;
}
//开启一个线程获取返回值
int main()
{
//std::launch::async自动创建一个线程,执行线程的入口函数,
// 返回一个std::future对象 std::future可以得到线程入口函数的返回结果,
// 使用方法get()即可 但是get函数只能调用一次,不能调用多次
//std::launch::deferred 打印结果表明使用defered,async是在主线程中调用的
std::future<int> fu = std::async(std::launch::deferred, task, 1, 2);
std::cout << std::this_thread::get_id() << std::endl;
std::cout << fu.get();
return 0;
}
//
3.packaged_task用于包装可调用目标,以便异步执行任务
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <future>
using namespace std;
int task(int a, int b)
{
int ret_a = a * a;
std::this_thread::sleep_for(std::chrono::seconds(3));
int ret_b = b * 2;
std::cout << std::this_thread::get_id() << std::endl;
return ret_a + ret_b;
}
int main()
{
std::cout << std::this_thread::get_id() << std::endl;
//packaged_task和future绑定在一起,方便在多线程中使用
std::packaged_task<int(int, int)> t(std::bind(task, 1, 2));
t(1, 2);
std::cout << t.get_future().get();
return 0;
}
上例的使用,packaged_task是在主线程中使用的。
那么std::async 、std::promise、std::packaged_task以及std::future之间有什么联系和区别呢?
通过 std::async 和 std::promise 以及以上内容可以看出:
- std::future是用于获取将来共享状态的运行结果或异常,相当于一个中间件,std::async 、std::promise、std::packaged_task都离不开它的帮助;
- std::packaged_task用于包装可调用目标,以便异步执行任务;
- std::promise用于设置共享状态的值,可以用于线程间交流,这个是比较特殊的。
- std::async是最优雅地方式启动任务异步执行;在多数情况下,建议使用asyn开启异步任务,而不是使用packaged_task方式。