异步调用策略:
C++允许我们强行指定异步活动的启动策略(launch policy)。
异步调用策略是一个枚举值,采用了C++11下,带class的枚举定义:
enum class launch:{async/*异步*/, deferred/*延期*/};
标准暂时仅要求提供两种策略。
launch::async表示本次异步操作强制要求立即开工,通常就是后台必须立即启动新线程以便执行任务;
launch::defered则强制要求本次异步操作暂时不开始,直到遇上调用future对象的get(),这种效果相当于延缓了任务的执行(原来代码也有拖延症)。
对应的async()函数版本,是在参数列表最前面新加一个入参:
future <T> async(std::launch policy, Function&& f, Args&&... args);
【危险】:发起异步操作的第三种策略
调用无policy入参版本的async()函数,使用的是什么策略?肯定不是launch::deferred,但也不一定是launch::async,而是交由程序临时决定。可能立即启动异步操作,也可能拖延一阵再开始,当然也有可能拖到get()函数被调用后才启动。后面我们称它为“临时决定”策略。
请牢记一点,仅在你的确不在意异步操作可能延迟的情况下,才使用无需指定策略的异步调用函数。
测试带调用策略版的async函数。首先定义一个简单的任务函数,用于在屏幕上输出100次指定短字符串:
void output(char const* s)
{
for(int i = 0; i < 100; ++i)
{
cout << s;
//确保每次输出不缓存,直接输出到屏幕
cout.flush();
}
}
void test4()
{
//小张,你到门口持续叫“呜”
std::future <void> future_1
//std::launch::async是异步策略
= std::async(std::launch::async, output, "呜");
//小李,你到门口持续叫“哦”
std::future <void> future_2
//std::launch::deferred是延期策略
= std::async(std::launch::deferred, output, "哦");
//领导我负责就地持续叫“哇”
output("哇");
future_1.get();
future_2.get();
}
运行效果:很明显,小李在开始时偷懒,它是直到future_2.get()时才开始叫。
【课堂作业】:异步代用lambda
请将以上那个热闹的例子做如下修改:在调用async时,直接传入lambda表达式。
这个例子还有一个地方需要稍加注意:output函数有入参,无返回值,因此在调用async是,需要填写额外的入参,也就是各种叫声,而返回的future需以void作为模板入参,这会在背后产生一个特殊的future,它的get()方法同样返回void。
另外,我们可能会不想重复写长长的future<T>类型,因此会用上auto,类似:
auto f = async(launch::async, output, "哼");
解答:
一:
二:
三: