c++ 多线程基础三–同步并发二

<future> 头文件中包含了以下几个类和函数:

  • Providers 类:std::promise, std::package_task
  • Futures 类:std::future,shared_future.
  • Providers 函数:std::async()
  • 其他类型:std::future_error, std::future_errc, std::future_status,
    std::launch.

1 std::asnyc 和 std::future

1.1 std::asnyc 是个对象模板,函数模型如下:

template<class Fn, class... Args>
future<typename result_of<Fn(Args...)>::type> async(launch policy, Fn&& fn, Args&&...args);

功能:第二个参数接收一个可调用对象(仿函数、lambda表达式、类成员函数、普通函数......)作为参数,并且异步或是同步执行他们;同时async自动创建新的线程。

  1. 对于是异步执行还是同步执行,由第一个参数的执行策略决定:

    • std::launch::async 传递的可调用对象异步执行,并马上执行线程,并创建新线程;

    • std::launch::deferred 传递的可调用对象同步执行,等待get或者wait才执行(即延迟执行),并没有创建新线程;

    • std::launch::async | std::launch::deferred 可以异步或是同步,取决于操作系统,我们无法控制;

    • 如果我们不指定策略,则相当于(3)。

  2. 对于执行结果:

    我们可以使用get、wait、wait_for、wait_until等待执行结束,区别是get可以获得执行的结果。如果选择异步执行策略,调用get时,如果异步执行没有结束,get会阻塞当前调用线程,直到异步执行结束并获得结果,如果异步执行已经结束,不等待获取执行结果;如果选择同步执行策略,只有当调用get函数时,同步调用才真正执行,这也被称为函数调用被延迟。同时get不能多次调用,get内部是move(移动语义)。

  3. 返回结果std::future的状态:

    • deffered:异步操作还没有开始;

    • ready:异步操作已经完成;

    • timeout:异步操作超时。
      实例:

    #include <iostream>
    #include <thread>
    #include <mutex>
    #include <chrono>
    #include <future>
    
    using namespace std;
    
    class A
    {
    public:
        int mythread(int input)
        {
            cout << "mythread get input :" << input << endl;
            cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
            std::chrono::milliseconds dura(5000);
            std::this_thread::sleep_for(dura);
            cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
    
            return 5;
        }
    
    };
    
    
    int main()
    {
        //std::thread t(hello);
        cout << "main thread:" << std::this_thread::get_id() << endl;
        //std::future<int> fu = std::async(mythread);
        A a;
        int input = 12;
        std::future<int>  fu = std::async(std::launch::deferred, &A::mythread, &a, input);
        std::cout << "checking, please wait" << endl;
        std::chrono::milliseconds span(6000);
        cout << "main thread get son thread stat:" << (int)fu.wait_for(span) << endl;
    
        int result = fu.get();
        cout << "main thread get son thread:" << result << endl;
    }
    

2 std::packaged_task

函数模型如下:

template< class > class packaged_task; //not defined
template< class R, class ...Args >
class packaged_task<R(Args...)>;

std::packaged_task 对象内部包含了两个最基本元素,一、被包装的任务(stored task),任务(task)是一个可调用的对象,如函数指针、成员函数指针或者函数对象,二、共享状态(shared state),用于保存任务的返回值,可以通过 std::future 对象来达到异步访问共享状态的效果。

可以通过 std::packged_task::get_future 来获取与共享状态相关联的 std::future 对象。在调用该函数之后,两个对象共享相同的共享状态,具体解释如下:

  • std::packaged_task 对象是异步 Provider,它在某一时刻通过调用被包装的任务来设置共享状态的值。
  • std::future 对象是一个异步返回对象,通过它可以获得共享状态的值,当然在必要的时候需要等待共享状态标志变为 ready.

std::packaged_task 的共享状态的生命周期一直持续到最后一个与之相关联的对象被释放或者销毁为止。

3 std::promise

promise 对象可以保存某一类型 T 的值,该值可被 future 对象读取(可能在另外一个线程中),因此 promise 也提供了一种线程同步的手段。在 promise 对象构造时可以和一个共享状态(通常是std::future)相关联,并可以在相关联的共享状态(std::future)上保存一个类型为 T 的值。

可以通过 get_future 来获取与该 promise 对象相关联的 future 对象,调用该函数之后,两个对象共享相同的共享状态(shared state)

  • promise 对象是异步 Provider,它可以在某一时刻设置共享状态的值。

  • future 对象可以异步返回共享状态的值,或者在必要的情况下阻塞调用者并等待共享状态标志变为 ready,然后才能获取共享状态的值。

    #include <iostream>       // std::cout
    #include <functional>     // std::ref
    #include <thread>         // std::thread
    #include <future>         // std::promise, std::future
    
    void print_int(std::future<int>& fut) {
        int x = fut.get(); // 获取共享状态的值.
        std::cout << "value: " << x << '\n'; // 打印 value: 10.
    }
    
    int main ()
    {
        std::promise<int> prom; // 生成一个 std::promise<int> 对象.
        std::future<int> fut = prom.get_future(); // 和 future 关联.
        std::thread t(print_int, std::ref(fut)); // 将 future 交给另外一个线程t.
        prom.set_value(10); // 设置共享状态的值, 此处和线程t保持同步.
        t.join();
        return 0;
    }
    

4 std::shared_future

std::shared_future 与 std::future 类似,但是 std::shared_future 可以拷贝、多个 std::shared_future 可以共享某个共享状态的最终结果(即共享状态的某个值或者异常)。shared_future 可以通过某个 std::future 对象隐式转换(参见 std::shared_future 的构造函数),或者通过 std::future::share() 显示转换,无论哪种转换,被转换的那个 std::future 对象都会变为 not-valid (即可以多次get到返回值)。

shared_future和 future区别

原文链接: https://www.cnblogs.com/lihaihui1991/p/14286395.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    c++ 多线程基础三--同步并发二

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/400351

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年4月14日 下午2:06
下一篇 2023年4月14日 下午2:06

相关推荐