当前位置:   article > 正文

C++并发编程之线程异步 std::future知识点总结

std::future

1、std::future介绍

类模板 std::future 提供访问异步操作结果的机制:(通过 std::async 、 std::packaged_task 或 std::promise 创建的)异步操作能提供一个 std::future 对象给该异步操作的创建者。然后,异步操作的创建者能用各种方法查询、等待或从 std::future 提取值。若异步操作仍未提供值,则这些方法可能阻塞。异步操作准备好发送结果给创建者时,它能通过修改链接到创建者的 std::future 的共享状态(例如 std::promise::set_value )进行。

注意, std::future 所引用的共享状态不与另一异步返回对象共享(与 std::shared_future 相反)。
—摘抄自https://www.apiref.com/cpp-zh/cpp/thread/future.html

这是官方的定义,那我们就看下具体std::future是怎么回事和怎么使用的吧。

std::future头文件如下:

 #include <future>
  • 1

std::future作用是希望线程返回一个结果,用于异步的操作。
下面,首先看下std::__basic_future 的定义:

 /// Common implementation for future and shared_future.
  template<typename _Res>
    class __basic_future : public __future_base
    {
    protected:
      typedef shared_ptr<_State_base>		__state_type;
      typedef __future_base::_Result<_Res>&	__result_type;

    private:
      __state_type 		_M_state;

    public:
      // Disable copying.
      __basic_future(const __basic_future&) = delete;
      __basic_future& operator=(const __basic_future&) = delete;

      bool
      valid() const noexcept { return static_cast<bool>(_M_state); }

      void
      wait() const
      {
        _State_base::_S_check(_M_state);
        _M_state->wait();
      }

      template<typename _Rep, typename _Period>
        future_status
        wait_for(const chrono::duration<_Rep, _Period>& __rel) const
        {
          _State_base::_S_check(_M_state);
          return _M_state->wait_for(__rel);
        }

      template<typename _Clock, typename _Duration>
        future_status
        wait_until(const chrono::time_point<_Clock, _Duration>& __abs) const
        {
          _State_base::_S_check(_M_state);
          return _M_state->wait_until(__abs);
        }

    protected:
      /// Wait for the state to be ready and rethrow any stored exception
      __result_type
      _M_get_result() const
      {
        _State_base::_S_check(_M_state);
        _Result_base& __res = _M_state->wait();
        if (!(__res._M_error == 0))
          rethrow_exception(__res._M_error);
        return static_cast<__result_type>(__res);
      }

      void _M_swap(__basic_future& __that) noexcept
      {
        _M_state.swap(__that._M_state);
      }

      // Construction of a future by promise::get_future()
      explicit
      __basic_future(const __state_type& __state) : _M_state(__state)
      {
        _State_base::_S_check(_M_state);
        _M_state->_M_set_retrieved_flag();
      }

      // Copy construction from a shared_future
      explicit
      __basic_future(const shared_future<_Res>&) noexcept;

      // Move construction from a shared_future
      explicit
      __basic_future(shared_future<_Res>&&) noexcept;

      // Move construction from a future
      explicit
      __basic_future(future<_Res>&&) noexcept;

      constexpr __basic_future() noexcept : _M_state() { }

      struct _Reset
      {
        explicit _Reset(__basic_future& __fut) noexcept : _M_fut(__fut) { }
        ~_Reset() { _M_fut._M_state.reset(); }
        __basic_future& _M_fut;
      };
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88

之后就是我们可以看到,std::future是继承std::__basic_future的,具体的定义如下:

 /// Primary template for future.
  template<typename _Res>
    class future : public __basic_future<_Res>
    {
      friend class promise<_Res>;
      template<typename> friend class packaged_task;
      template<typename _Fn, typename... _Args>
        friend future<typename result_of<_Fn(_Args...)>::type>
        async(launch, _Fn&&, _Args&&...);

      typedef __basic_future<_Res> _Base_type;
      typedef typename _Base_type::__state_type __state_type;

      explicit
      future(const __state_type& __state) : _Base_type(__state) { }

    public:
      constexpr future() noexcept : _Base_type() { }

      /// Move constructor
      future(future&& __uf) noexcept : _Base_type(std::move(__uf)) { }

      // Disable copying
      future(const future&) = delete;
      future& operator=(const future&) = delete;

      future& operator=(future&& __fut) noexcept
      {
        future(std::move(__fut))._M_swap(*this);
        return *this;
      }

      /// Retrieving the value
      _Res
      get()
      {
        typename _Base_type::_Reset __reset(*this);
        return std::move(this->_M_get_result()._M_value());
      }

      shared_future<_Res> share();
    };

  /// Partial specialization for future<R&>
  template<typename _Res>
    class future<_Res&> : public __basic_future<_Res&>
    {
      friend class promise<_Res&>;
      template<typename> friend class packaged_task;
      template<typename _Fn, typename... _Args>
        friend future<typename result_of<_Fn(_Args...)>::type>
        async(launch, _Fn&&, _Args&&...);

      typedef __basic_future<_Res&> _Base_type;
      typedef typename _Base_type::__state_type __state_type;

      explicit
      future(const __state_type& __state) : _Base_type(__state) { }

    public:
      constexpr future() noexcept : _Base_type() { }

      /// Move constructor
      future(future&& __uf) noexcept : _Base_type(std::move(__uf)) { }

      // Disable copying
      future(const future&) = delete;
      future& operator=(const future&) = delete;

      future& operator=(future&& __fut) noexcept
      {
        future(std::move(__fut))._M_swap(*this);
        return *this;
      }
      /// Retrieving the value
      _Res&
      get()
      {
        typename _Base_type::_Reset __reset(*this);
        return this->_M_get_result()._M_get();
      }
      shared_future<_Res&> share();
    };
  /// Explicit specialization for future<void>
  template<>
    class future<void> : public __basic_future<void>
    {
      friend class promise<void>;
      template<typename> friend class packaged_task;
      template<typename _Fn, typename... _Args>
        friend future<typename result_of<_Fn(_Args...)>::type>
        async(launch, _Fn&&, _Args&&...);
      typedef __basic_future<void> _Base_type;
      typedef typename _Base_type::__state_type __state_type;
      explicit
      future(const __state_type& __state) : _Base_type(__state) { }
    public:
      constexpr future() noexcept : _Base_type() { }
      /// Move constructor
      future(future&& __uf) noexcept : _Base_type(std::move(__uf)) { }
      // Disable copying
      future(const future&) = delete;
      future& operator=(const future&) = delete;

      future& operator=(future&& __fut) noexcept
      {
        future(std::move(__fut))._M_swap(*this);
        return *this;
      }
      /// Retrieving the value
      void
      get()
      {
        typename _Base_type::_Reset __reset(*this);
        this->_M_get_result();
      }
      shared_future<void> share();
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118

在C11中,std::future有两种类型的模板。
1、唯一期望值unique futures, std::future<> std::future的实例只能关联一个事件。
2、共享期望值shared futures, std::shared_future<> std::shared_future可以关联多个事件。

异步执行的三种状态如下:

  /// Status code for futures
  enum class future_status
  {
    ready,//异步操作已经完成
    timeout,//异步操作超时
    deferred//异步操作还没有开始
  };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这是基本的std::future的定义,下面我们需要看下std::async的定义。
std::async用于启动一个异步执行策略

/// async
  template<typename _Fn, typename... _Args>
    future<typename result_of<_Fn(_Args...)>::type>
    async(launch __policy, _Fn&& __fn, _Args&&... __args)
    {
      typedef typename result_of<_Fn(_Args...)>::type result_type;
      std::shared_ptr<__future_base::_State_base> __state;
      if ((__policy & (launch::async|launch::deferred)) == launch::async)
	{
	  __state = __future_base::_S_make_async_state(std::__bind_simple(
              std::forward<_Fn>(__fn), std::forward<_Args>(__args)...));
	}
      else
	{
	  __state = __future_base::_S_make_deferred_state(std::__bind_simple(
              std::forward<_Fn>(__fn), std::forward<_Args>(__args)...));
	}
      return future<result_type>(__state);
    }

  /// async, potential overload
  template<typename _Fn, typename... _Args>
    inline future<typename result_of<_Fn(_Args...)>::type>
    async(_Fn&& __fn, _Args&&... __args)
    {
      return async(launch::async|launch::deferred, std::forward<_Fn>(__fn),
		   std::forward<_Args>(__args)...);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  /// Launch code for futures
  enum class launch
  {
    async = 1, //保证异步行为,即传递函数在单独的线程中执行。
    deferred = 2 //当其他线程调用get()/waite()访问共享状态时,调用非异步的行为。
  };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、std::future重要成员函数介绍

operator= 移动future对象

share 将*this转移共享状态给shared_future并返回它

get获取返回结果
状态
valid() 检查future是否拥有共享状态
wait() 等待执行结果变成可以获得
wait_for() 等待结果,如果在超过指定时间间隔后仍然无法得到结果,则立即返回
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3、std::future用法示例

/*************************************************************************
	> File Name: thread_future.cpp
	> Author: 小和尚敲木鱼
	> Mail:  
	> Created Time: Tue 21 Sep 2021 02:13:25 AM PDT
 ************************************************************************/

#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include <mutex>
#include <future>
#include <chrono>

using namespace std;
/*****************************文件说明***********************************
************************************************************************/
class Base
{
public:
	int baseThread1(int param)
	{
		int value = 5;
		std::cout <<__func__ <<"Reiver param" << param << std::endl;
		std::cout << __func__ <<"Current Thread ID = "<< std::this_thread::get_id() << std::endl;
		std::chrono::milliseconds  sleep_time(500);
		std::this_thread::sleep_for(sleep_time);
		std::cout << "Current Thread ID ="<< std::this_thread::get_id() << std::endl;
		std::cout << "Return = " << (value + param) << std::endl;
		return (value + param);
	}
	int baseThread2()
	{
		int value = 5;
		std::cout <<__func__ <<"Reiver param"<< std::endl;
		std::cout << __func__ <<"Current Thread ID = "<< std::this_thread::get_id() << std::endl;
		std::chrono::milliseconds  sleep_time(500);
		std::this_thread::sleep_for(sleep_time);
		std::cout << "Current Thread ID ="<< std::this_thread::get_id() << std::endl;
		std::cout << "Return = " << value<< std::endl;
		return (value);
	}
};

int main(int agc,char * agv[])
{
	int temp = 20;
	Base base_test;
	std::cout << "Main Thread ID = " << std::this_thread::get_id() << std::endl;
	std::future<int> result = std::async(std::launch::async, &Base::baseThread1, &base_test, temp); 

	std::cout << "Continue...." << std::endl;
	result.wait();
	//阻塞在这里,知道result能够获得并得到最后的结果。
	//当共享状态值是不可以用时,调用wait接口可以一直阻塞,直到共享状态变为"就绪"时,就变为可以用了。
	std::cout << "Final result = " << result.get() << std::endl;
	return 0;
}
//OUT
//Main Thread ID = 140522049050432
//Continue....
//baseThread1Reiver param20
//baseThread1Current Thread ID = 140522031671040
//Current Thread ID =140522031671040
//Return = 25 
//Final result = 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

std::futere查询状态

//查询future的状态
std::future_status status;
do {
    status = future.wait_for(std::chrono::seconds(1));
    switch(status)
    {
	    case std::future_status::deferred:
	    	std::cout << "std::future_status::deferred" <<std::endl;
	    break;
	    case std::future_status::timeout:
	    	std::cout << "std::future_status::timeout" <<std::endl;
	    break;
	    case std::future_status::ready:
	    	std::cout << "std::future_status::ready" <<std::endl;
	    break;
	    default:
	    	std::cout << "none status" << std::endl;
	    break;
    }
} while (status != std::future_status::ready);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

4、总结

一般来说std::future都是配合std::async、std::packaged_task和std::promise一起使用。返回其异步执行的结果。使用起来也是非常的银杏。
Todo:
后续补充std::future::wait_for的示例。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/922398
推荐阅读
  

闽ICP备14008679号