C++11 promise

2023-10-27

一 promise
  • 前文 C++11 async 可知,异步操作的方式之一,是通过 std::async 接口调用可执行对象,然后通过 std::future 获得结果。
  • 另一种常见方式是在指定的 std::thread 中执行,如何获取在 std::thread 中的执行结果?办法之一就是通过 std::promise。
二 定义
// 头文件 <future>
template< class R > class promise; (1)(C++11) // 空模板
template< class R > class promise<R&>; (2)(C++11) // 非 void 特化,用于在线程间交流对象
template<>          class promise<void>; (3)(C++11) // void 特化,用于交流无状态事件
  • 类模板 std::promise 提供存储值或异常的设施。

  • promise 对象与其 get_future() 接口返回的 future 对象构成 promise-future 交流通道。通道的 promise对象与 future 对象关联同一共享状态(shared state), promise 对象是通道的 push 端,future 对象是通道的 pop 端。promise 存储值或异常到共享状态中,使共享状态就绪,future 通过get()异步获得结果。

  • promise 对共享状态的三种处理

    使就绪: promise 存储结果或异常于共享状态。标记共享状态为就绪,并解除阻塞任何等待于与该共享状态关联的 future 上的线程。
    释放: promise 放弃其对共享状态的引用。若这是最后一个这种引用,则销毁共享状态。除非这是 std::async 所创建的未就绪的共享状态,否则此操作不阻塞。
    抛弃: promise 存储以 std::future_errc::broken_promise 为 error_code 的 std::future_error 类型异常,令共享状态为就绪,然后释放它。

  • std::promise 只应当使用一次。

    Note that the std::promise object is meant to be used only once.

三 成员函数
  1. 构造

    promise(); (1)(C++11)
    template< class Alloc >
    promise( std::allocator_arg_t, const Alloc& alloc ); (2)(C++11)
    promise( promise&& other ) noexcept; (3)(C++11)
    promise( const promise& other ) = delete; (4)(C++11) // 不可复制构造
    
  2. 析构

    ~promise(); (C++11) // 抛弃共享状态
    
  • 若共享状态就绪,则释放它。若共享状态未就绪,则抛弃。
  1. operator=

    promise& operator=( promise&& other ) noexcept; (1)(C++11)
    promise& operator=( const promise& rhs ) = delete; (2)(C++11) // 不可复制赋值
    
四 get_future
std::future<T> get_future(); (C++11)
  • 若无共享状态,或已调用 get_future 则抛出异常。即仅可调用一次
  • 可通过 get_future 间接获得结果。
五 设置结果
1. set_value
  • 设置结果为指定值, 并使状态就绪。
// (仅为泛型 promise 模板的成员)
void set_value( const R& value ) (1)(C++11)
void set_value( R&& value ); (2)(C++11)

// (仅为 promise<R&> 模板特化的成员)
void set_value( R& value ); (3)(C++11)
// (仅为 promise<void> 模板特化的成员)
void set_value(); (4)(C++11)
  • demo
#include <algorithm>  // sort
#include <future>     // future promise
#include <iostream>   // cout cin endl
#include <iterator>   // istream_iterator back_inserter
#include <sstream>    // istringstream
#include <thread>     // thread
#include <vector>     // vector
#include <numeric>    // accumulate

void accumulate(std::vector<int>::iterator first,
                std::vector<int>::iterator last,
                std::promise<int> accumulate_promise) {
  int sum = std::accumulate(first, last, 0);
  accumulate_promise.set_value(sum);  // 原子地存储 num 到共享状态,并令状态就绪
}
int main() {
  std::istringstream iss_numbers{"3 4 1 42 23 -23 93 2 -289 93"};
  std::vector<int> numbers;
  {
    // set_value (4)
    std::promise<void> numbers_promise;
    std::future<void> numbers_future = numbers_promise.get_future();
   
    std::thread t([&] {
      std::copy(std::istream_iterator<int>{iss_numbers},
                std::istream_iterator<int>{}, std::back_inserter(numbers));
      numbers_promise.set_value(); // 使状态就绪
    });
   
    numbers_future.wait();
    std::sort(numbers.begin(), numbers.end());
   
    for (int num : numbers)
      std::cout << num << ' ';
    std::cout << std::endl;
   
    t.join();
  }
  {
    // set_value (1)
    std::promise<int> accumulate_promise;
    std::future<int> accumulate_future = accumulate_promise.get_future();
    std::thread t(accumulate, numbers.begin(), numbers.end(),
                            std::move(accumulate_promise));

    std::cout << "result=" << accumulate_future.get() << '\n';
    t.join(); 
  }
}
  • 结果
-289 -23 1 2 3 4 23 42 93 93
result=-51
2. set_value_at_thread_exit
  • 原子地存储 value 到共享状态,而不立即令状态就绪。在当前线程退出时,销毁所有拥有线程局域存储期的对象后,再令状态就绪。
// (仅为泛型 promise 模板的成员)
void set_value_at_thread_exit( const R& value );(1)	(C++11)
void set_value_at_thread_exit( R&& value );(2)	(C++11)

// (仅为 promise<R&> 模板特化的成员)
void set_value_at_thread_exit( R& value );(3)	(C++11)
// (仅为 promise<void> 模板特化的成员)
void set_value_at_thread_exit();(4)	(C++11)
  • demo
// set_value_at_thread_exit
using namespace std::chrono_literals;
std::promise<int> p;
std::future<int> f = p.get_future();
std::thread([&p] {
  std::this_thread::sleep_for(1s);
  p.set_value_at_thread_exit(9);
}).detach();

std::cout << "Waiting..." << std::flush;
f.wait();
std::cout << "Done!\nResult is: " << f.get() << std::endl;
  • 结果
Waiting...Done!
Result is: 9
3. set_exception
  • 存储异常指针 p 到共享状态中,并令状态就绪。
void set_exception( std::exception_ptr p );(C++11)
  • demo
// set_exception
std::promise<int> p;
std::future<int> f = p.get_future();

std::thread t([&p] {
  try {
    throw std::runtime_error("Example");
  } catch (...) {
    try {
      // store anything thrown in the promise
      p.set_exception(std::current_exception());
    } catch (...) {
    }  // set_exception() may throw too
  }
});

try {
  std::cout << f.get();
} catch (const std::exception& e) {
  std::cout << "Exception from the thread: " << e.what() << std::endl;
}
t.join();
  • 结果
Exception from the thread: Example
4. set_exception_at_thread_exit
  • 存储异常指针 p 到共享状态中,而不立即使状态就绪。在当前线程退出时,销毁所有拥有线程局域存储期的变量后,再零状态就绪。
六 参考

cppreference-promise

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++11 promise 的相关文章

随机推荐

  • 编译 OneFlow 模型

    本篇文章译自英文文档 Compile OneFlow Models tvm 0 14 dev0 documentation 作者是 BBuf Xiaoyu Zhang GitHub 更多 TVM 中文文档可访问 Apache TVM 是一个
  • 3月6日服务器例行维护公告,2014年3月6日停机维护公告

    亲爱的玩家 为了保证服务器的稳定和服务质量 新大话西游2 将于2014年3月6日早上8 00停机 进行每周例行的维护工作 维护时间为早上08 00至09 30 同时 本次停机还将发布最新的客户端补丁 patch2 0 476 如果在维护期间
  • Java高级编程——多线程(JDK5新增创建线程方式Callable,线程池)

    创建线程的第三 四种方式 一 实现Callable接口 1 1与Runnable相比 1 2实现步骤 创建Callable接口实现类 重写call方法 新建实现类对象 将实现类对象作为参数传递待FutureTask的构造器中 创建Futur
  • 使用redis进行用户接口访问时间次数限制

    使用redis进行用户接口访问时间次数限制 假设一个用户 用IP判断 每分钟访问某一个服务接口的次数不能超过10次 import org apache commons lang3 StringUtils import org slf4j L
  • Android Studio一直Waiting for build to finish

    今天安卓的gradle文件出现问题 所以将C Users Administrator gradle删除 接下来出现下图的问题 这是由于安卓缺少gradle文件 图片来自https blog csdn net Hanghang article
  • 手撕yolo3系列——详解主干网络darknet53代码(详细注释)

    完整代码百度云直达链接 包含预训练权重 小白注释 https pan baidu com s 1US6e93OaCYOghmF21v0UIA 提取码 z8at 参考链接 注 代码是大神的代码 在此基础上添加了详细的小白注释 方便我以后阅读
  • Keil调试即全速运行/断点不停的其中一个原因

    平台 芯片 STM32F767IGT6 环境 Keil 5 14 00 问题 keil 下载程序可以执行 调试时刚进调试就上电运行 打断点不停 但是程序正常在跑 可以单步调试 原因 Jlink硬件版本和驱动的问题 解决 之前电脑使用stm3
  • image.shape[0],image.shape[1],image.shape[2]

    import cv2 image cv2 imread D shape bmp print image shape 0 print image shape 1 print image shape 2 结果 300 200 3 其中shape
  • mysql8.0安装之后,无法使用密码正常登陆

    修改方法 重置密码 以下为步骤 1 以管理员身份先关闭mysql服务器 net stop mysql 删除mysql目录下data文件夹 如果有就删除 2 在mysql目录下输入 mysqld initialize user mysql c
  • python如何判断是否为整数

    python 判断是否为整数的方法 1 使用 type 函数判断 代码为 type name bases dict 2 使用 isinstance 函数判断 代码为 isinstance object classinfo 本教程操作环境 w
  • java 生成随机字母数字组合

    import java util Random public class RandomTest 方法1 生成随机数字和字母组合 param length return public static String getCharAndNumr
  • 让UE4中的TextRender永远面向摄像机,就像Billboard那样!

    让UE4中的TextRender永远面向摄像机 就像Billboard那样 让UE4中的TextRender永远面向摄像机就像Billboard那样 前言 Find Look At 函数 BillBoard 材质编程 前言 最近找了个兼职
  • socket网络编程(二)(tcp udp)

    1 socket大概介绍 Socket的中文翻译过来就是 套接字 套接字是什么 我们先来看看它的英文含义 插座 Socket就像一个电话插座 负责连通两端的电话 进行点对点通信 让电话可以进行通信 端口就像插座上的孔 端口不能同时被其他进程
  • 负电压实现方法

    目录 方法一 负压芯片实现 方法二 Buck Boost电路方法 方法三 用Buck芯片产生出负压 结论 方法一 负压芯片实现 在电子市场或电子网站上 可以很容易找到使用charge pump方式的负电压芯片 但是输入的电压最高只有5 5V
  • 中青杯数学建模竞赛是什么级别的比赛_比赛介绍

    一 背景介绍 美国大学生数学建模竞赛 MCM ICM 由美国数学及其应用联合会主办 是唯一的国际性数学建模竞赛 也是世界范围内最具影响力的数学建模竞赛 为现今各类数学建模竞赛之鼻祖 二 活动目的 MCM ICM的宗旨是鼓励大学师生对范围并不
  • Variational Auto-encoder(VAE)变分自编码器-Pytorch

    import os import torch import torch nn as nn import torch nn functional as F import torchvision from torchvision import
  • 领地人生服务器维护,领地人生gm代码是什么 领地人生服务器指令

    领地人生是一款非常真实的沙盒生存类游戏 游戏中玩家将要成为一名生存者 需要通过不断造房屋 猎杀野兽生存下来 游戏中的一些指令可以加快你的建造速度 下面就和小编一起来看看吧 GM password 开 关 GM模式 例如 gm mysecre
  • Numpy数组排序

    numpy sort a axis 1 kind quicksort order None 返回已排序新数组 参数说明 axis 可选参数 取值整数或None 若axis为None 数组先偏平化 降维 再排序 若axis N 表示沿着数组的
  • Android小项目集合100多个

    是学习和联系Android小项目的使用资料 排名完全是根据 GitHub 搜索 Java 语言选择 Best Match 得到的结果 然后过滤了跟 Android 不相关的项目 所以排名并不具备任何官方效力 仅供参考学习 方便初学者快速了解
  • C++11 promise

    目录 一 promise 二 定义 三 成员函数 四 get future 五 设置结果 1 set value 2 set value at thread exit 3 set exception 4 set exception at t