美文网首页
C++并发高级接口std::async和std::future

C++并发高级接口std::async和std::future

作者: 土豆吞噬者 | 来源:发表于2019-08-27 22:23 被阅读0次

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");
}

相关文章

网友评论

      本文标题:C++并发高级接口std::async和std::future

      本文链接:https://www.haomeiwen.com/subject/cvzyectx.html