目录
一、问题引出
从《c++标准库》(第2版)看到一个std::async的例子。演示了使用 std::async 和std::future的异步任务执行。
#include <future>
#include <thread>
#include <chrono>
#include <random>
#include <iostream>
#include <exception>
using namespace std;
void doSomething (char c)
{
// random-number generator (use c as seed to get different sequences)
default_random_engine dre(c);
uniform_int_distribution<int> id(10,1000);
// loop to print character after a random period of time
for (int i=0; i<10; ++i) {
this_thread::sleep_for(chrono::milliseconds(id(dre)));
cout.put(c).flush();
}
}
int main()
{
cout << "starting 2 operations asynchronously" << endl;
// start two loops in the background printing characters . or +
auto f1 = async([]{ doSomething('.'); });
auto f2 = async([]{ doSomething('+'); });
// if at least one of the background tasks is running
if (f1.wait_for(chrono::seconds(0)) != future_status::deferred ||
f2.wait_for(chrono::seconds(0)) != future_status::deferred) {
// poll until at least one of the loops finished
while (f1.wait_for(chrono::seconds(0)) != future_status::ready &&
f2.wait_for(chrono::seconds(0)) != future_status::ready) {
//...;
this_thread::yield(); // hint to reschedule to the next thread
}
}
cout.put('\n').flush();
// wait for all loops to be finished and process any exception
try {
f1.get();
f2.get();
}
catch (const exception& e) {
cout << "\nEXCEPTION: " << e.what() << endl;
}
cout << "\ndone" << endl;
}
二、关键点解释
1.生成随机数
default_random_engine dre(c);
:创建一个默认的随机数生成器dre
,并使用字符c
作为种子。这样不同的调用会得到不同的随机数序列。uniform_int_distribution<int> id(10,1000);
:创建一个均匀整数分布对象id
,用于生成范围在 10 到 1000 之间的随机整数。
2.异步启动两个操作
auto f1 = async([]{ doSomething('.'); });
auto f2 = async([]{ doSomething('+'); });
std::async
是一个用于异步执行任务的函数模板。它会启动一个新的线程(或者使用线程池中的线程)来执行传入的可调用对象(这里是 lambda 表达式)。f1
和f2
是std::future
对象,用于获取异步操作的结果。这里的异步操作是调用doSomething
函数,分别传入字符.
和+
。
3.检查异步任务是否为延迟执行并轮询任务状态
if (f1.wait_for(chrono::seconds(0)) != future_status::deferred ||
f2.wait_for(chrono::seconds(0)) != future_status::deferred) {
while (f1.wait_for(chrono::seconds(0)) != future_status::ready &&
f2.wait_for(chrono::seconds(0)) != future_status::ready) {
this_thread::yield(); // hint to reschedule to the next thread
}
}
cout.put('\n').flush();
f1.wait_for(chrono::seconds(0))
和f2.wait_for(chrono::seconds(0))
:检查f1
和f2
对应的异步任务的状态,chrono::seconds(0)
表示不等待,立即返回任务状态。future_status::deferred
表示任务是延迟执行的。如果至少有一个任务不是延迟执行的,则进入内层循环。内层
while
循环会不断检查f1
和f2
的状态,直到至少有一个任务完成(状态为future_status::ready
)。this_thread::yield();
:提示操作系统将当前线程的执行权让给其他线程,避免忙等待。
4.等待所有任务完成并处理异常
try {
f1.get();
f2.get();
}
catch (const exception& e) {
cout << "\nEXCEPTION: " << e.what() << endl;
}
f1.get()
和f2.get()
:阻塞当前线程,直到f1
和f2
对应的异步任务完成,并获取任务的结果。如果任务抛出异常,get()
函数会重新抛出该异常。catch (const exception& e)
:捕获可能抛出的异常,并输出异常信息。
三、总结
这段代码的主要功能是异步启动两个任务,每个任务会随机暂停一段时间后输出一个字符,程序会等待至少一个任务完成,最后等待所有任务完成并处理可能的异常。