一. std::promise和std::package_task

(一)共享状态、提供者和管理者

  1. // CLASS TEMPLATE _Promise
  2. template <class _Ty>
  3. class _Promise { // class that implements core of promise
  4. public:
  5. _Promise(_Associated_state<_Ty>* _State_ptr)
  6. : _State(_State_ptr, false), _Future_retrieved(false) { // construct from associated asynchronous state object
  7. }
  8.  
  9. _Promise(_Promise&& _Other)
  10. : _State(_STD move(_Other._State)),
  11. _Future_retrieved(_Other._Future_retrieved) { // construct from rvalue _Promise object
  12. }
  13.  
  14. _Promise& operator=(_Promise&& _Other) { // assign from rvalue _Promise object
  15.  
  16. _State = _STD move(_Other._State);
  17. _Future_retrieved = _Other._Future_retrieved;
  18. return *this;
  19. }
  20.  
  21. ~_Promise() noexcept { // destroy
  22. }
  23.  
  24. void _Swap(_Promise& _Other) { // exchange with _Other
  25. _State._Swap(_Other._State);
  26. _STD swap(_Future_retrieved, _Other._Future_retrieved);
  27. }
  28.  
  29. const _State_manager<_Ty>& _Get_state() const { // return reference to associated asynchronous state object
  30. return _State;
  31. }
  32. _State_manager<_Ty>& _Get_state() { // return reference to associated asynchronous state object
  33. return _State;
  34. }
  35.  
  36. _State_manager<_Ty>& _Get_state_for_set() { // return reference to associated asynchronous state object, or
  37. // throw exception if not valid for setting state
  38. if (!_State.valid()) {
  39. _Throw_future_error(make_error_code(future_errc::no_state));
  40. }
  41.  
  42. return _State;
  43. }
  44.  
  45. _State_manager<_Ty>& _Get_state_for_future() { // return reference to associated asynchronous state object, or
  46. // throw exception if not valid for retrieving future
  47. if (!_State.valid()) {
  48. _Throw_future_error(make_error_code(future_errc::no_state));
  49. }
  50.  
  51. if (_Future_retrieved) {
  52. _Throw_future_error(make_error_code(future_errc::future_already_retrieved));
  53. }
  54.  
  55. _Future_retrieved = true;
  56. return _State;
  57. }
  58.  
  59. bool _Is_valid() const noexcept { // return status
  60. return _State.valid();
  61. }
  62.  
  63. bool _Is_ready() const { // return ready status
  64. return _State._Is_ready();
  65. }
  66.  
  67. bool _Is_ready_at_thread_exit() const { // return ready at thread exit status
  68. return _State._Is_ready_at_thread_exit();
  69. }
  70.  
  71. _Promise(const _Promise&) = delete;
  72. _Promise& operator=(const _Promise&) = delete;
  73.  
  74. private:
  75. _State_manager<_Ty> _State;
  76. bool _Future_retrieved;
  77. };
  78.  
  79. // CLASS TEMPLATE promise
  80. template <class _Ty>
  81. class promise { // class that defines an asynchronous provider that holds a value
  82. public:
  83. promise() : _MyPromise(new _Associated_state<_Ty>) { // construct
  84. }
  85.  
  86. template <class _Alloc>
  87. promise(allocator_arg_t, const _Alloc& _Al)
  88. : _MyPromise(_Make_associated_state<_Ty>(_Al)) { // construct with allocator
  89. }
  90.  
  91. promise(promise&& _Other) noexcept
  92. : _MyPromise(_STD move(_Other._MyPromise)) { // construct from rvalue promise object
  93. }
  94.  
  95. promise& operator=(promise&& _Other) noexcept { // assign from rvalue promise object
  96. promise(_STD move(_Other)).swap(*this);
  97. return *this;
  98. }
  99.  
  100. ~promise() noexcept { // destroy
  101. if (_MyPromise._Is_valid() && !_MyPromise._Is_ready()
  102. && !_MyPromise._Is_ready_at_thread_exit()) { // exception if destroyed before function object returns
  103. future_error _Fut(make_error_code(future_errc::broken_promise));
  104. _MyPromise._Get_state()._Set_exception(_STD make_exception_ptr(_Fut), false);
  105. }
  106. }
  107.  
  108. void swap(promise& _Other) noexcept { // exchange with _Other
  109. _MyPromise._Swap(_Other._MyPromise);
  110. }
  111.  
  112. _NODISCARD future<_Ty> get_future() { // return a future object that shares the associated
  113. // asynchronous state
  114. return future<_Ty>(_MyPromise._Get_state_for_future(), _Nil());
  115. }
  116.  
  117. void set_value(const _Ty& _Val) { // store result
  118. _MyPromise._Get_state_for_set()._Set_value(_Val, false);
  119. }
  120.  
  121. void set_value_at_thread_exit(const _Ty& _Val) { // store result and block until thread exit
  122. _MyPromise._Get_state_for_set()._Set_value(_Val, true);
  123. }
  124.  
  125. void set_value(_Ty&& _Val) { // store result
  126. _MyPromise._Get_state_for_set()._Set_value(_STD forward<_Ty>(_Val), false);
  127. }
  128.  
  129. void set_value_at_thread_exit(_Ty&& _Val) { // store result and block until thread exit
  130. _MyPromise._Get_state_for_set()._Set_value(_STD forward<_Ty>(_Val), true);
  131. }
  132.  
  133. void set_exception(exception_ptr _Exc) { // store result
  134. _MyPromise._Get_state_for_set()._Set_exception(_Exc, false);
  135. }
  136.  
  137. void set_exception_at_thread_exit(exception_ptr _Exc) { // store result and block until thread exit
  138. _MyPromise._Get_state_for_set()._Set_exception(_Exc, true);
  139. }
  140.  
  141. promise(const promise&) = delete;
  142. promise& operator=(const promise&) = delete;
  143.  
  144. private:
  145. _Promise<_Ty> _MyPromise;
  146. };
  147.  
  148. template <class _Ret, class... _ArgTypes>
  149. class packaged_task<_Ret(_ArgTypes...)> { // class that defines an asynchronous provider that returns the
  150. // result of a call to a function object
  151. public:
  152. using _Ptype = typename _P_arg_type<_Ret>::type;
  153. using _MyPromiseType = _Promise<_Ptype>;
  154. using _MyStateManagerType = _State_manager<_Ptype>;
  155. using _MyStateType = _Packaged_state<_Ret(_ArgTypes...)>;
  156.  
  157. packaged_task() noexcept : _MyPromise() { // construct
  158. }
  159.  
  160. template <class _Fty2, class = enable_if_t<!is_same_v<_Remove_cvref_t<_Fty2>, packaged_task>>>
  161. explicit packaged_task(_Fty2&& _Fnarg)
  162. : _MyPromise(new _MyStateType(_STD forward<_Fty2>(_Fnarg))) { // construct from rvalue function object
  163. }
  164.  
  165. packaged_task(packaged_task&& _Other) noexcept
  166. : _MyPromise(_STD move(_Other._MyPromise)) { // construct from rvalue packaged_task object
  167. }
  168.  
  169. packaged_task& operator=(packaged_task&& _Other) noexcept { // assign from rvalue packaged_task object
  170.  
  171. _MyPromise = _STD move(_Other._MyPromise);
  172. return *this;
  173. }
  174.  
  175. #if _HAS_FUNCTION_ALLOCATOR_SUPPORT
  176. template <class _Fty2, class _Alloc, class = enable_if_t<!is_same_v<_Remove_cvref_t<_Fty2>, packaged_task>>>
  177. packaged_task(allocator_arg_t, const _Alloc& _Al, _Fty2&& _Fnarg)
  178. : _MyPromise(_Make_packaged_state<_MyStateType>(
  179. _STD forward<_Fty2>(_Fnarg), _Al)) { // construct from rvalue function object and allocator
  180. }
  181. #endif // _HAS_FUNCTION_ALLOCATOR_SUPPORT
  182.  
  183. ~packaged_task() noexcept { // destroy
  184. _MyPromise._Get_state()._Abandon();
  185. }
  186.  
  187. void swap(packaged_task& _Other) noexcept { // exchange with _Other
  188. _STD swap(_MyPromise, _Other._MyPromise);
  189. }
  190.  
  191. _NODISCARD bool valid() const noexcept { // return status
  192. return _MyPromise._Is_valid();
  193. }
  194.  
  195. _NODISCARD future<_Ret> get_future() { // return a future object that shares the associated
  196. // asynchronous state
  197. return future<_Ret>(_MyPromise._Get_state_for_future(), _Nil());
  198. }
  199.  
  200. void operator()(_ArgTypes... _Args) { // call the function object
  201. if (_MyPromise._Is_ready()) {
  202. _Throw_future_error(make_error_code(future_errc::promise_already_satisfied));
  203. }
  204.  
  205. _MyStateManagerType& _State = _MyPromise._Get_state_for_set();
  206. _MyStateType* _Ptr = static_cast<_MyStateType*>(_State._Ptr());
  207. _Ptr->_Call_immediate(_STD forward<_ArgTypes>(_Args)...);
  208. }
  209.  
  210. void make_ready_at_thread_exit(_ArgTypes... _Args) { // call the function object and block until thread exit
  211. if (_MyPromise._Is_ready()) {
  212. _Throw_future_error(make_error_code(future_errc::promise_already_satisfied));
  213. }
  214.  
  215. _MyStateManagerType& _State = _MyPromise._Get_state_for_set();
  216. if (_State._Ptr()->_Already_has_stored_result()) {
  217. _Throw_future_error(make_error_code(future_errc::promise_already_satisfied));
  218. }
  219.  
  220. _MyStateType* _Ptr = static_cast<_MyStateType*>(_State._Ptr());
  221. _Ptr->_Call_deferred(_STD forward<_ArgTypes>(_Args)...);
  222. }
  223.  
  224. void reset() { // reset to newly constructed state
  225. _MyStateManagerType& _State = _MyPromise._Get_state_for_set();
  226. _MyStateType* _MyState = static_cast<_MyStateType*>(_State._Ptr());
  227. function<_Ret(_ArgTypes...)> _Fnarg = _MyState->_Get_fn();
  228. _MyPromiseType _New_promise(new _MyStateType(_Fnarg));
  229. _MyPromise._Get_state()._Abandon();
  230. _MyPromise._Swap(_New_promise);
  231. }
  232.  
  233. packaged_task(const packaged_task&) = delete;
  234. packaged_task& operator=(const packaged_task&) = delete;
  235.  
  236. private:
  237. _MyPromiseType _MyPromise;
  238. };

【std::promise/std::package_task源码摘要】

  1.“共享状态”作为异步结果的传输通道,由std::async、std::promise和std::package_task等提供(Provider),并交由future/shared_future管理。Provider将计算结果写入“共享状态”对象,而future/shared_future通过get()函数来读取该结果。

  2. std::promise用于包装一个值,将数据和future绑定起来,方便线程赋值。而std::package_task用来包装一个可调用对象,将函数与future绑定以便异步调用。

  3. std::async、std::promise和std::package_task都是“共享状态”对象的创建者,它们创建“共享状态”类型有所不同。

  (1)std::async:创建_Deferred_async_state和_Task_async_state类型的共享状态。

  (2)std::promise:创建_Associated_state类型的“共享状态”。这种类型比较简单,内部只能保存某个类型的值(如返回值)。

  (3)std::package_task:创建_Package_state类型的“共享状态”,这种类型内部是通过std::function来可以包装可调用对象的

  4. std::promise和std::package_task都只有移动语义而没有拷贝语义

(二)std::promise类

  1. 用来保存某一类型的值,也可以用来保存线程函数的返回值,该值可被future读取。它为线程同步提供了一种手段。

  2. 可以通过 get_future 来获取future 对象,该对象与promise通过“共享状态”这个通道进行异步结果传输。std::promise通常在某个时间点通过设置一个值或异常对象, future通过调用get()来获取这个结果。

  3. set_value_at_thread_exit函数:设置共享状态的值,但不会将共享状态的标志设置为ready。当有当线程退出时,该标志位才设置为true,同时唤醒所有阻塞在future的get()函数的线程。

  4. 如果销毁std::promise时未设置值,则会存入一个异常。

(三)std::package_task类

  1. std::package_task 用来包装可调用对象,其本身也是一个可调用对象(因为重载了operator()(Args…args)函数。它可以作为线程函数传递给std::thread,或传给需要可调用对象的另一个函数,或者干脆直接调用。这与std::function类似,但std::package_task会将其包装的可调用对象执行结果(返回值)保存起来,并传递给了future对象

  2. 通过get_future()返回一个与“共享状态”相关联的future对象。其他线程可以通过std::package_task对象在“共享状态”上设置某个值或者异常。

  3. make_ready_at_thread_exit(Arg...args):该函数会调用被包装的任务,并向任务传递参数,类似于std::package_task的operator()成员函数,但不同的是make_read_at_thread_exit并不会立即设置“共享状态”的ready标志,而是在线程退出时才设置它

  4. reset()函数会重置“共享状态”,但是保留了之前被包装的任务。它使得package_task可以被重复使用,这点与std::promise一次性使用不同。

  5. std::package_task对象一般与std::thread配合使用,而不是std::async。如果要使用std::async运行任务,就没有理由去创建std::package_task对象。因为std::async调用时,内部会创建一个基类为_Packaged_state类 “共享状态”的子类对象,而std::package_task也会创建_Packaged_state类的对象。可见std::async能够在调用任务执行之前就做到std::package_task能做到的任何事情,也可以避免重复创建“共享状态”对象。

【编程实验】初探std::promise和std::pack_task

  1. #include <iostream>
  2. #include <future>
  3. #include <thread>
  4. #include <chrono>
  5. #include <queue>
  6.  
  7. using namespace std;
  8.  
  9. void func(std::promise<int>& pr, int param)
  10. {
  11. int res = param * ;
  12. pr.set_value_at_thread_exit(res); //线程退出时,设置需要输出的值
  13. }
  14.  
  15. //计算阶乘
  16. int factorial(int n)
  17. {
  18. std::this_thread::sleep_for(std::chrono::milliseconds());
  19.  
  20. if (n == )
  21. return ;
  22.  
  23. return n * factorial(n - );
  24. }
  25.  
  26. void get_result(std::future<int>& fut) //获取结果
  27. {
  28. while (fut.wait_for(std::chrono::milliseconds()) == std::future_status::timeout) {
  29. std::cout << ".";
  30. }
  31. std::cout << std::endl;
  32. std::cout << "the factorial result is " << fut.get() << std::endl;
  33. }
  34.  
  35. int main()
  36. {
  37. //1. std::promise/std::future配合使用
  38.  
  39. //1.1 主线程等待子线程的结果
  40. std::promise<int> pr1;
  41. std::future<int> fut1 = pr1.get_future();
  42.  
  43. std::thread t1(func, std::ref(pr1), );
  44. t1.join(); //等待t1线程退出
  45.  
  46. std::cout << "The func output: " << fut1.get() << std::endl;
  47. //1.2 子线程等待主线程的计算结果
  48. std::promise<int> pr2;
  49. std::future<int> fut2 = pr2.get_future(); //创建通道
  50.  
  51. std::thread t2([](std::future<int>& fut) {
  52. int res = fut.get();
  53. cout <<"thread id: "<<std::this_thread::get_id() << " get result " << res << endl;
  54. }, std::ref(fut2));
  55.  
  56. std::this_thread::sleep_for(std::chrono::milliseconds());
  57.  
  58. pr2.set_value();
  59. t2.join();
  60.  
  61. //2. std::package_task与std::future配合使用
  62. //2.1 直接将package_task作为函数对象使用
  63. std::packaged_task<double(int, int)> task1([](int a, int b) {
  64. return std::pow(a, b);
  65. });
  66.  
  67. std::future<double> res = task1.get_future();
  68.  
  69. task1(, );
  70.  
  71. std::cout << "task_lambda: " << res.get() << endl;
  72.  
  73. //2.2 将std::package_task作为任务传递给std::thread线程
  74. std::packaged_task<int(int)> task2(factorial);
  75. std::future<int> fut3 = task2.get_future();
  76.  
  77. std::thread t3(std::ref(task2), ); //t3线程计算7的阶乘
  78. std::thread t4(get_result, std::ref(fut3));
  79. t3.join();
  80. t4.join();
  81.  
  82. task2.reset(); //重置task,使得task2可以被重复使用
  83. std::future<int> fut5 = task2.get_future();
  84. std::thread t5(std::ref(task2), ); //计算8的阶乘
  85. cout << fut5.get() << endl;
  86. t5.join();
  87.  
  88. //3.std::async与std::future配合使用
  89. std::future<int> fut6 = std::async(std::launch::async, factorial, );
  90. fut6.wait();
  91.  
  92. cout <<"aync calc result is: " << fut6.get() << endl;
  93.  
  94. return ;
  95. }
  96. /*输出结果
  97. The func output: 50
  98. thread id: 6532 get result 100
  99. task_lambda: 512
  100. .................................
  101. the factorial result is 5040
  102. 40320
  103. aync calc result is: 5040
  104. */

二. std::promise/std::package_task的应用

(一)一次性事件及建模

  1. 一个线程在完成其任务之前,可能需要等待特定的一次性事件的发生。在等待期间,线程可以去轮询事件是否发生,也可以去做其他任务。C++标准库使用std::future为这类一次性事件建模。

  2.一旦事件发生,future变为就绪,而std::future的get/wait()只能被调用一次,无法重复使用。如果多线程等待同一个事件,就需要使用std::shared_future,当事件发生时所有相关的shared_future对象均会变为就绪,并且可以访问其关联的任务结果。

  3.期值对象本身并不提供同步访问,当多个线程需要访问一个独立的期值对象时,必须使用互斥量或类似同步机制对访问进行保护。而如果仅为了实现一次性的事件通信,基于条件变量的设计会要求多余的互斥量和标志位,这显然不够干净利落,而使用期值可以很好的处理这个问题。

(二)线程间传递任务(以GUI消息处理为例)

  1. 在GUI编程中,当一个线程计算完结果,它要发出一条信息给GUI线程,以通知更新界面。

  2. std::package_task提供了实现这种功能的方法,且不需要发送一条自定义信息给GUI线程,而是将函数包装成任务,并传递到GUI线程,使任务在GUI线程中运行。

【编程实验】std::promise和std::package_task的应用

  1. #include <iostream>
  2. #include <future>
  3. #include <thread>
  4. #include <mutex>
  5. #include <queue>
  6.  
  7. using namespace std;
  8.  
  9. //1.一次性事件及建模(以实现暂停状态启动的线程为例)
  10. //创建暂停状态的线程:std::thread类创建的线程,一启动线程就运行起来。但是如果希望在线程运行前设置优先级和内核亲和性,
  11. //就需要一个可以创建一个暂停的线程,然后通过其提供的native_handle成员,利用平台底层API配置这些线程特征。为达到这一
  12. //目的,可以利用std::promise / std::future提供的一次性机制来实现暂停状态的线程。
  13. class MyThread
  14. {
  15. private:
  16. std::thread mThread;
  17. std::promise<void> mPromise;
  18. std::future<void> mFuture;
  19. bool bStart;
  20. public:
  21. template<typename Fn, typename ...ArgTypes>
  22. MyThread(Fn&& fn, ArgTypes&&... args):bStart(false)
  23. {
  24. mFuture = mPromise.get_future();
  25.  
  26. mThread = std::move(std::thread([this, &fn, &args...] {
  27. mFuture.wait();
  28. std::forward<Fn>(fn)(std::forward<ArgTypes>(args)...);
  29. }));
  30. }
  31.  
  32. void start()
  33. {
  34. if (!bStart) {
  35. mPromise.set_value();
  36. bStart = true;
  37. }
  38. }
  39.  
  40. void join()
  41. {
  42. mThread.join();
  43. }
  44.  
  45. void detach()
  46. {
  47. mThread.detach();
  48. }
  49.  
  50. bool joinable() {
  51. return mThread.joinable();
  52. }
  53. };
  54.  
  55. //2. 利用shared_future处理多个反应任务
  56. //反应任务
  57. std::mutex g_mtx;
  58. void reach()
  59. {
  60. std::lock_guard<std::mutex> lck(g_mtx);
  61. cout << "thread(id= " <<std::this_thread::get_id() <<") react"<< endl;
  62. }
  63.  
  64. //检测任务(可处理多个反应任务)
  65. void detech()
  66. {
  67. std::promise<void> pr;
  68. std::shared_future<void> sf = pr.get_future().share();
  69. std::vector<std::thread> vec; //反应任务的容器
  70.  
  71. for (int i = ; i < ; ++i)
  72. {
  73. vec.emplace_back([sf] //在sf按值传递,在其副本上wait
  74. {
  75. sf.wait();
  76. reach();
  77. });
  78. }
  79.  
  80. //... //注意,如果此处抛出异常,则detech会失去响应
  81.  
  82. pr.set_value(); //让所有线程取消暂停
  83.  
  84. for (auto& t : vec) {
  85. t.join();
  86. }
  87. }
  88.  
  89. //3. gui消息处理(在线程间传递任务,而不是消息)
  90. class MessageManager
  91. {
  92. std::queue<std::shared_ptr<std::function<void()>>> mQueue;
  93. std::mutex mtx;
  94. bool bShutdown = false;
  95. public:
  96. void shutDown() { bShutdown = true; }
  97.  
  98. //将任务包装成package_task
  99. template<typename Fn, typename... Args>
  100. std::future<std::result_of_t<Fn && (Args&& ...)>> //postTask函数的返回值类型,future配合package_task使用
  101. postTask(Fn&& fn, Args&& ...args)
  102. {
  103. using Ret = std::result_of_t <Fn && (Args && ...)>; //Fn函数的返回值类型
  104.  
  105. std::lock_guard<std::mutex> lck(mtx);
  106.  
  107. ////将任务包装成package_task类型(注意,由于package_task为只移动类型,不能复制。这里在堆上创建)
  108. auto ptrPA = std::make_shared<std::packaged_task<Ret()>>(std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...));
  109. auto fut = ptrPA->get_future();
  110.  
  111. //利用lambda将“std::packaged_task<Ret()>”重新包装成queue队列所需的元素类型:std::function<void()>共享指针类型
  112. auto pTask = std::make_shared<std::function<void()>>([ptrPA]()->void {(*ptrPA)(); });
  113.  
  114. mQueue.push(pTask);
  115.  
  116. return fut;
  117. }
  118.  
  119. void guiThread()
  120. {
  121. while (!bShutdown)
  122. {
  123. //... //处理其它gui界面消息
  124.  
  125. //获取并执行用户任务
  126. std::shared_ptr<std::function<void()>> task;
  127. {
  128. std::lock_guard<std::mutex> lk(mtx);
  129. if (mQueue.empty())
  130. continue;
  131.  
  132. task = mQueue.front(); //取出队列中的用户任务
  133. mQueue.pop();
  134. }
  135. (*task)(); //执行任务
  136. }
  137. }
  138. };
  139.  
  140. int main()
  141. {
  142. cout << "main thread running..." << endl;
  143.  
  144. //1. 以暂停状态启动的线程
  145. MyThread th([](int x, int y) {
  146. int res = x + y;
  147.  
  148. cout << x << " + " << y << " = " << res << endl;
  149. return res;
  150. }, , );
  151.  
  152. th.start();
  153.  
  154. th.join();
  155.  
  156. //2.处理多反应任务(在shared_future上等待)
  157. detech();
  158.  
  159. //3. 在线程间传递任务
  160. MessageManager mm;
  161. std::thread guiThread(&MessageManager::guiThread,&mm);
  162.  
  163. auto fut1 = mm.postTask([](int x, int y)->int { return x + y; }, , );
  164. auto fut2 = mm.postTask([](int x, int y, int z) {return x * y * z; }, , , );
  165. auto fut3 = mm.postTask([](const std::string& str) {return str; }, "SantaClaus");
  166. cout << fut1.get() << endl; //
  167. cout << fut2.get() << endl; //
  168. cout << fut3.get() << endl; //SantaClaus
  169.  
  170. mm.shutDown();
  171.  
  172. guiThread.join();
  173.  
  174. return ;
  175. }
  176. /*输出结果
  177. main thread running...
  178. 10 + 20 = 30
  179. thread(id= 8792) react
  180. thread(id= 2600) react
  181. thread(id= 2604) react
  182. thread(id= 13384) react
  183. thread(id= 14864) react
  184. thread(id= 14884) react
  185. thread(id= 13588) react
  186. thread(id= 13516) react
  187. thread(id= 11956) react
  188. thread(id= 13540) react
  189. 3
  190. 6000
  191. SantaClaus
  192. */

第28课 “共享状态”提供者(std::promise/std::package_task)的更多相关文章

  1. 第27课 “共享状态”及其管理者(std::future/std::shared_future)

    一. “共享状态” (一)“共享状态”对象 1. 用于保存线程函数及其参数.返回值以及新线程状态等信息.该对象通常创建在堆上,由std::async.std::promise和std::package ...

  2. C++并发编程之std::async(), std::future, std::promise, std::packaged_task

    c++11中增加了线程,使得我们可以非常方便的创建线程,它的基本用法是这样的: void f(int n); std::thread t(f, n + 1); t.join(); 但是线程毕竟是属于比 ...

  3. C++11 并发指南四(<future> 详解一 std::promise 介绍)

    前面两讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三(std::mutex 详解)>分别介绍了 std::thread 和 std::m ...

  4. C++11之std::future和std::promise和std::std::packaged_task

    为什么C++11引入std::future和std::promise?C++11创建了线程以后,我们不能直接从thread.join()得到结果,必须定义一个变量,在线程执行时,对这个变量赋值,然后执 ...

  5. C++并发低级接口:std::thread和std::promise

    std::thread和std::promise 相比std::async,std::thread就原始多了.thread一定会创建新线程(而不是像async那样创建的时候可能不会,后面才创建新线程( ...

  6. C++11 并发指南四(<future> 详解一 std::promise 介绍)(转)

    前面两讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三(std::mutex 详解)>分别介绍了 std::thread 和 std::m ...

  7. 【C++并发实战】(三) std::future和std::promise

    std::future和std::promise std::future std::future期待一个返回,从一个异步调用的角度来说,future更像是执行函数的返回值,C++标准库使用std::f ...

  8. C++11之std::future和std::promise

    为什么C++11引入std::future和std::promise?C++11创建了线程以后,我们不能直接从thread.join()得到结果,必须定义一个变量,在线程执行时,对这个变量赋值,然后执 ...

  9. C++11 并发指南四(<future> 详解三 std::future & std::shared_future)

    上一讲<C++11 并发指南四(<future> 详解二 std::packaged_task 介绍)>主要介绍了 <future> 头文件中的 std::pack ...

随机推荐

  1. 图片服务器FastDFS的安装及使用

    FastDFS介绍 FastDFS是用c语言编写的一款开源的分布式文件系统.FastDFS为互联网量身定制,充分考虑了冗余备份.负载均衡.线性扩容等机制,并注重高可用.高性能等指标,使用FastDFS ...

  2. 【JS】---5 JS通过事件隐藏显示元素

    JS通过事件隐藏显示元素 在开发中,很多时候我们需要点击事件,才显示隐藏元素.那如何做到页面刚开始就把标签隐藏. 有两种方法: (1) display:none    <div id=" ...

  3. 2019-11-25-加强版在国内分发-UWP-应用正确方式-通过win32安装UWP应用

    原文:2019-11-25-加强版在国内分发-UWP-应用正确方式-通过win32安装UWP应用 title author date CreateTime categories 加强版在国内分发 UW ...

  4. 一文让你读懂Synchronized底层实现,秒杀面试官

    本文为死磕Synchronized底层实现第三篇文章,内容为轻量级锁实现. 轻量级锁并不复杂,其中很多内容在偏向锁一文中已提及过,与本文内容会有部分重叠. 另外轻量级锁的背景和基本流程在概论中已有讲解 ...

  5. 洛谷 p1541乌龟棋

    洛谷 p1541乌龟棋 题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行NN个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第NN格是终点,游戏 ...

  6. 个人项目wc(Java)

                                                      个人项目(Java) 一丶Github地址:https://github.com/SAH2019/S ...

  7. Python Scrapy在windows上的安装方法

    如果想要学习爬虫,肯定会了解Scrapy,但安装Scrapy的方法相对于安装其他第三方库麻烦一点. 下面总结一下在我的电脑上安装Scrapy的方法,我的电脑是Windows10,32位操作系统.有如下 ...

  8. git tag介绍

    我们常常在代码发版时,使用git 创建一个tag ,这样一个不可修改的历史代码版本就像被我们封存起来一样,不论是运维发布拉取,或者以后的代码版本管理,都是十分方便的. git的tag功能git 下打标 ...

  9. 使用阿里云生成的pem密钥登录

    我用的阿里云生成的ssh密钥,服务器上已有公钥,私钥为.pem文件,下载在本地,网上都说要转换为.ppk再用,其实用secure不必转换 一..pem和.ppk文件区别 .pem 密钥通用格式  .p ...

  10. LGBMClassifier参数

    本文链接:https://blog.csdn.net/starmoth/article/details/845867091.boosting_type=‘gbdt’# 提升树的类型 gbdt,dart ...