std::async可以让一个可调用对象在一个独立线程中运行,std::future允许你等待线程结束并获取其结果,下面代码中,async尝试将函数立刻异步启动于一个分离的线程,然后返回一个future对象允许你取得函数结果或异常。
当future对象的get方法被调用时,以下三种事情之一会发生:
- 如果函数被async启动于一个分离线程中并且已结束,你会立刻获得结果。
- 如果函数被async启动于一个分离线程中但还未结束,get会等待函数结束后获得结果。
- 如果函数尚未启动,它会被强迫启动如同一个同步调用,get会等待函数结束后获得结果。
#include <future>
#include <thread>
#include <chrono>
int printTag(const string& tag)
{
int ret = 0;
for (int i = 0; i < 10; ++i) {
this_thread::sleep_for(chrono::milliseconds(100));
cout << tag;
ret += i;
}
return ret;
}
int main()
{
//babababaababbababaab90
future<int> result1(async([] {return printTag("a"); }));
int result2 = printTag("b");
cout << result1.get() + result2 << endl;
system("pause");
}
async可以使用launch策略async要求明确以异步方式启动目标函数,如果异步调用在此无法实现(例如当前环境不支持多线程或无法创建新的线程),程序会抛出一个std::system_error异常。
future<int> result1(async(launch::async, [] {return printTag("a"); }));
使用launch策略deferred可以强制延缓执行目标函数直到对future对象调用get或wait。
int main()
{
//bbbbbbbbbbaaaaaaaaaa90
future<int> result1(async(launch::deferred,[] {return printTag("a"); }));
int result2 = printTag("b");
cout << result1.get() + result2 << endl;
system("pause");
}
如果不将async的结果赋值出去(deferred策略除外),调用者会在此等待直到目标函数结束。
int main()
{
//aaaaaaaaaabbbbbbbbbb
async([] {return printTag("a"); });
int result2 = printTag("b");
system("pause");
}
线程中未被处理的异常会被捕捉到future对象中,然后在调用get时再次抛出。
void throwExceptionFunc()
{
try {
throw exception();
}
catch (...) {
cout << "catch exception in sub thread" << endl;
}
}
int main()
{
future<void> result1(async(throwExceptionFunc));
try {
result1.get();
}catch (...) {
cout << "catch exception in main thread" << endl;
}
system("pause");
}
一个future对象只能调用一次get方法,在那之后future对象就处于无效状态,这种状态可以用valid方法来检测。
future还提供一组接口允许我们等待后台操作完成而不需要处理其结果,这些接口可以被调用一次以上,分别是wait,wait_for(等待一段时间),wait_until(等待直到某特定时间点到达),这些接口不会抛出线程中未处理的异常。
wait_for,wait_until会返回以下三种值:
- future_status::deferred:async使用了deferred策略,且没调用过wait或get方法,这种情况下会立刻返回。
- future_status::timeout:操作被异步启动但尚未结束,而等待的时间已到。
- future_status::ready:操作成功完成。
void printFunc()
{
while (true) {
this_thread::sleep_for(chrono::seconds(1));
cout << "runing..." << endl;
}
}
int main()
{
future<void> result1(async(printFunc));
cout << (int)result1.wait_for(chrono::seconds(10))<< endl;
cout << "wait finished!"<<endl;
system("pause");
}
使用lambda时可以使用值捕获或引用捕获传递实参给函数,也可以直接使用async传递实参(等同于值捕获)。
void modifyStr(string& str)
{
str+= "_modifyed";
}
void printStr(const string& str)
{
cout << str << endl;
}
int main()
{
string testStr = "hello";
auto result1=async(printStr, testStr);//使用async传递实参
result1.wait();
auto result2 = async([=]()mutable{modifyStr(testStr); });//值捕获
result2.wait();
cout << testStr << endl;//hello
auto result3 = async([&] {modifyStr(testStr); });//引用捕获
result3.wait();
cout << testStr << endl;//hello_modifyed
system("pause");
}
future只能调用一次get方法,而shared_future可以多次调用get方法(返回相同结果),这在多个线程想处理同一个结果时非常有用。
int queryNumber()
{
cout << "read number:";
int num;
cin >> num;
if (!cin) {
return 0;
}
return num;
}
void printChar(char c, shared_future<int> f)
{
int num = f.get();
for (int i = 0; i < num; i++) {
this_thread::sleep_for(chrono::milliseconds(100));
cout << c;
}
}
int main()
{
shared_future<int> f = async(queryNumber);
auto f1 = async(launch::async, printChar, 'A', f);
auto f2 = async(launch::async, printChar, 'B', f);
auto f3 = async(launch::async, printChar, 'C', f);
f1.wait();
f2.wait();
f3.wait();
system("pause");
}
网友评论