4.1 线程异步和通信

4.1.1 promise和future

  • promise 用于异步传输变量

    std::promise 提供存储异步通信的值,再通过其对象创建的std::future异步获得结果 std::promise 只能使用一次。void set_value(_Ty&& _Val) 设置传递值,智能调用一次

  • std:future 提供访问异步操作结果的机制

    get()阻塞等待promise set_value的值

  • 代码演示

    1. void TestFuture(promise<string> p) {
    2. ps.set_value("TestFuture value");
    3. }
    4. int main(){
    5. }
  1. #include <future>
  2. #include <iostream>
  3. #include <string>
  4. #include <thread>
  5. using namespace std;
  6. void TestFuture(promise<string> p)
  7. {
  8. cout << "begin TestFuture" << endl;
  9. this_thread::sleep_for(3s);
  10. cout << "begin set value" << endl;
  11. p.set_value("TestFuture value");
  12. this_thread::sleep_for(3s);
  13. cout << "end TestFuture" << endl;
  14. }
  15. int main(int argc, char* argv[])
  16. {
  17. // 异步函数变量
  18. promise<string> p;
  19. // 用来获取线程异步值获取
  20. auto future = p.get_future();
  21. auto th = thread(TestFuture, move(p)); // 将p转移到线程函数中,不能使用复制(直接传入p)
  22. cout << "begin future.get()" << endl;
  23. cout << "future get() = " << future.get() << endl;
  24. cout << "end future.get()" << endl;
  25. th.join();
  26. getchar();
  27. return 0;
  28. }
  29. /*
  30. begin future.get()
  31. begin TestFuture // 等到了3s
  32. begin set value // 开始读值, 调用get的时候是阻塞的,等调用完,子线程才结束
  33. future get() = TestFuture value
  34. end future.get()
  35. end TestFuture
  36. */

4.1.2 packaged_task 异步调用函数打包

  • ackaged_task 包装函数为一个对象,用于异步调用。其返回值能通过std::future 对象访问
  • 与bind的区别,可异步调用,函数访问和获取返回值分开调用 ```cpp

    include

    include

    include

    include

using namespace std;

string TestPack(int index) { cout << “begin test pack “ << index << endl; this_thread::sleep_for(2s); // 模拟业务逻辑 return “TestPack return”; }

int main(int argc, char* argv[]) { packaged_task task(TestPack); // 模板里是函数类型 返回值类型参数类型 auto result = task.get_future(); // 返回值结果和上面模板的一样 task(100);

  1. // 以上同时打印出来, 是同步调用的
  2. cout << "begin result get" << endl;
  3. cout << "result get " << result.get() << endl;
  4. getchar();
  5. return 0;

}

/ begin test pack 100 begin result get result get TestPack return /

加上线程,可看到 get() 那是堵塞的
```cpp
#include <future>
#include <iostream>
#include <string>
#include <thread>

using namespace std;

string TestPack(int index)
{
    cout << "begin test pack " << index << endl;
    this_thread::sleep_for(2s); // 模拟业务逻辑
    return "TestPack return";
}

int main(int argc, char* argv[])
{
    packaged_task<string(int)> task(TestPack); // 模板里是函数类型 返回值类型参数类型
    auto result = task.get_future(); // 返回值结果和上面模板的一样

    thread th(move(task), 100);

    cout << "begin result get" << endl;
    cout << "result get " << result.get() << endl;
    th.join();

    getchar();
    return 0;
}
/*
    begin result get
    result get begin test pack 100
    TestPack return
*/
#include <future>
#include <iostream>
#include <string>
#include <thread>

using namespace std;

string TestPack(int index)
{
    cout << "begin test pack " << index << endl;
    this_thread::sleep_for(2s); // 模拟业务逻辑
    return "TestPack return";
}
int main(int argc, char* argv[])
{
    packaged_task<string(int)> task(TestPack); // 模板里是函数类型 返回值类型参数类型
    auto result = task.get_future(); // 返回值结果和上面模板的一样

    thread th(move(task), 100);

    cout << "begin result get" << endl;

    //测试是否超时
    for (int i = 0; i < 30; i++) { // 如果该成1秒,会看出它是超时的
        result.wait_for(100ms);
    }

    if (result.wait_for(100ms) == future_status::timeout) {
        cout << "wait result timeout" << endl;
    } else {
        cout << "result get " << result.get() << endl;
    }
    th.join();
    getchar();
    return 0;
}

4.1.3 async

C++11 异步运行一个函数,并返回保有其结果的 std::future

  • launch::deferred 延迟执行,在调用wait和get时,调用函数代码
  • launch::async 创建线程(默认)
  • 返回的线程函数的返回值类型的std::future(std:future<线程函数的返回值类型>)
  • re.get() 获取结果,会堵塞等待
    double result = 0;
    cout << "Async task with lambda triggered, thread: " << this_thread::get_id() << endl;
    // auto f2 = async(launch::async, [&result](){});
    
    ```cpp

    include

    include

    include

    include

using namespace std;

string TestAsync(int index) { cout << index << “ begin in TestAsync: “ << this_thread::get_id() << endl; this_thread::sleep_for(2s); return “TestAsync string return.”; }

int main(int argc, char* argv[]) { // 创建异步线程

// 情况一:不创建线程启动异步任务
cout << "main thread id: " << this_thread::get_id() << endl;
auto future = async(launch::deferred, TestAsync, 100);
this_thread::sleep_for(100ms);
cout << "begin future get" << endl;
cout << "future.get() = " << future.get() << endl;
cout << "end future get" << endl;
/*
    main thread id: 1
    begin future get
    future.get() = 100 begin in TestAsync: 1
    TestAsync string return.
    end future get
*/

// 情况2:创建线程启动异步任务
cout << "main thread id: " << this_thread::get_id() << endl;
auto future2 = async(TestAsync, 101);
this_thread::sleep_for(100ms);
cout << "begin future get" << endl;
cout << "future.get() = " << future2.get() << endl;
cout << "end future get" << endl;
getchar();
return 0;

}

```