C++ Futures与Promises线程使用示例讲解

目录
  • 一、说明
  • 二、示例

一、说明

Futures 和 Promises 是将数据从一个线程传递到另一个线程的工具。虽然这也可以通过其他功能来完成,例如全局变量、futures 和 promises 在没有它们的情况下也能工作。此外,您不需要自己处理同步。

未来是一个从另一个线程接收值的变量。如果您访问未来以获取值,您可能需要等到其他线程提供该值。 Boost.Thread 提供 boost::future 来定义未来。该类定义了一个成员函数 get() 来获取值。 get() 是一个阻塞函数,可能需要等待另一个线程。

要在未来设置一个值,您需要使用一个承诺,因为 boost::future 不提供成员函数来设置一个值。

二、示例

Boost.Thread 提供类 boost::promise,它有一个成员函数 set_value()。您总是将 future 和 promise 成对使用。您可以使用 get_future() 从承诺中获得未来。您可以在不同的线程中使用未来和承诺。如果在一个线程中的 promise 中设置了一个值,则可以在另一个线程中从 future 中获取它。

示例 44.14。使用 boost::future 和 boost::promise

#define BOOST_THREAD_PROVIDES_FUTURE
#include <boost/thread.hpp>
#include <boost/thread/future.hpp>
#include <functional>
#include <iostream>
void accumulate(boost::promise<int> &p)
{
  int sum = 0;
  for (int i = 0; i < 5; ++i)
    sum += i;
  p.set_value(sum);
}
int main()
{
  boost::promise<int> p;
  boost::future<int> f = p.get_future();
  boost::thread t{accumulate, std::ref(p)};
  std::cout << f.get() << '\n';
}

Example44.14

示例使用未来和承诺。未来 f 是从承诺 p 中接收到的。然后将对 promise 的引用传递给执行 accumulate() 函数的线程 t。 accumulate() 计算 0 到 5 之间所有数字的总和并将其保存在 promise 中。在 main() get() 中调用 future 将总数写入标准输出。

未来 f 和承诺 p 是相关联的。当对未来调用 get() 时,将返回使用 set_value() 存储在承诺中的值。因为该示例使用两个线程,所以可能会在 accumulate() 调用 set_value() 之前在 main() 中调用 get()。在这种情况下,get() 会阻塞,直到使用 set_value() 将一个值存储在 promise 中。

示例 44.14 显示 10。

accumulate() 必须调整为在线程中执行。它必须采用 boost::promise 类型的参数并将结果存储在其中。示例 44.15 引入了 boost::packaged_task,这是一个将值从任何函数转发到未来的类,只要该函数通过 return 返回结果即可。

示例 44.15。使用 boost::packaged_task

#define BOOST_THREAD_PROVIDES_FUTURE
#include <boost/thread.hpp>
#include <boost/thread/future.hpp>
#include <utility>
#include <iostream>
int accumulate()
{
  int sum = 0;
  for (int i = 0; i < 5; ++i)
    sum += i;
  return sum;
}
int main()
{
  boost::packaged_task<int> task{accumulate};
  boost::future<int> f = task.get_future();
  boost::thread t{std::move(task)};
  std::cout << f.get() << '\n';
}

Example44.15

示例 44.15 与前一个类似,但这次没有使用 boost::promise。相反,此示例使用类 boost::packaged_task,它与 boost::promise 一样提供返回未来的成员函数 get_future()。

boost::packaged_task 的构造函数期望将在线程中执行的函数作为参数,但 boost::packaged_task 本身并不启动线程。必须将类型为 boost::packaged_task 的对象传递给 boost::thread 的构造函数,以便在新线程中执行该函数。

boost::packaged_task 的优点是它在未来存储函数的返回值。你不需要调整一个函数来在未来存储它的值。 boost::packaged_task 可以看作是一个适配器,它可以存储未来任何函数的返回值。

虽然该示例摆脱了 boost::promise,但以下示例也没有使用 boost::packaged_task 和 boost::thread。

示例 44.16。使用 boost::async()

#define BOOST_THREAD_PROVIDES_FUTURE
#include <boost/thread.hpp>
#include <boost/thread/future.hpp>
#include <iostream>
int accumulate()
{
  int sum = 0;
  for (int i = 0; i < 5; ++i)
    sum += i;
  return sum;
}
int main()
{
  boost::future<int> f = boost::async(accumulate);
  std::cout << f.get() << '\n';
}

在示例 44.16 中,accumulate() 被传递给函数 boost::async()。这个函数统一了 boost::packaged_task 和 boost::thread。它在新线程中启动 accumulate() 并返回未来。

可以将启动策略传递给 boost::async()。这个附加参数决定了 boost::async() 是在新线程中还是在当前线程中执行该函数。如果您传递 boost::launch::async,boost::async() 将启动一个新线程;这是默认行为。如果您传递 boost::launch::deferred,该函数将在调用 get() 时在当前线程中执行。

尽管 Boost 1.56.0 允许将 boost::launch::async 或 boost::launch::deferred 传递给 boost::async(),但尚未实现在当前线程中执行函数。如果您传递 boost::launch::deferred,程序将终止。

到此这篇关于C++ Futures与Promises线程使用示例讲解的文章就介绍到这了,更多相关C++ Futures与Promises内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2022-11-18

C++中多线程的执行顺序如你预期吗

目录 一个简单的例子 诡异的输出结果 你看到的执行顺序不是真的执行顺序 你看到的执行顺序还不是真正的执行顺序 C++多线程内存模型 一个简单的例子 先来看一个多线程的例子: 如图所示,我们将变量x和y初始化为0,然后在线程1中执行: x = 1, m = y; 同时在线程2中执行: y = 1, n = x; 当两个线程都执行结束以后,m和n的值分别是多少呢? 对于已经工作了n年.写过无数次并发程序的的我们来说,这还不是小case吗?让我们来分析一下,大概有三种情况: 如果程序先执行了x = 1

C++实现线程同步的四种方式总结

目录 内核态 互斥变量 事件对象 资源信号量 用户态 关键代码 内核态 互斥变量 互斥对象包含一个使用数量,一个线程ID和一个计数器.其中线程ID用于标识系统中的哪个线程当前拥有互斥对象,计数器用于指明该线程拥有互斥对象的次数. 创建互斥对象:调用函数CreateMutex.调用成功,该函数返回所创建的互斥对象的句柄. 请求互斥对象所有权:调用函数WaitForSingleObject函数.线程必须主动请求共享对象的所有权才能获得所有权. 释放指定互斥对象的所有权:调用ReleaseMutex函

C++同步线程实现示例详解

目录 一.同步线程 二.独占访问示例 一.同步线程 虽然使用多线程可以提高应用程序的性能,但通常也会增加复杂性.如果同时执行多个函数,则必须同步对共享资源的访问.一旦应用程序达到一定大小,这将涉及大量的编程工作.本节介绍Boost.Thread提供的用于同步线程的类. 二.独占访问示例 示例 44.7.使用 boost::mutex 的独占访问 #include <boost/thread.hpp> #include <boost/chrono.hpp> #include <

java中常见的6种线程池示例详解

之前我们介绍了线程池的四种拒绝策略,了解了线程池参数的含义,那么今天我们来聊聊Java 中常见的几种线程池,以及在jdk7 加入的 ForkJoin 新型线程池 首先我们列出Java 中的六种线程池如下 线程池名称 描述 FixedThreadPool 核心线程数与最大线程数相同 SingleThreadExecutor 一个线程的线程池 CachedThreadPool 核心线程为0,最大线程数为Integer. MAX_VALUE ScheduledThreadPool 指定核心线程数的定时

Python异步爬虫多线程与线程池示例详解

目录 背景 异步爬虫方式 多线程,多进程(不建议) 线程池,进程池(适当使用) 单线程+异步协程(推荐) 多线程 线程池 背景 当对多个url发送请求时,只有请求完第一个url才会接着请求第二个url(requests是一个阻塞的操作),存在等待的时间,这样效率是很低的.那我们能不能在发送请求等待的时候,为其单独开启进程或者线程,继续请求下一个url,执行并行请求 异步爬虫方式 多线程,多进程(不建议) 好处:可以为相关阻塞的操作单独开启线程或者进程,阻塞操作就可以异步会执行 弊端:不能无限制开

Python网络爬虫中的同步与异步示例详解

一.同步与异步 #同步编程(同一时间只能做一件事,做完了才能做下一件事情) <-a_url-><-b_url-><-c_url-> #异步编程 (可以近似的理解成同一时间有多个事情在做,但有先后) <-a_url-> <-b_url-> <-c_url-> <-d_url-> <-e_url-> <-f_url-> <-g_url-> <-h_url-> <--i_ur

Spring Boot之@Async异步线程池示例详解

目录 前言 一. Spring异步线程池的接口类 :TaskExecutor 二.简单使用说明 三.定义通用线程池 1.定义线程池 2.异步方法使用线程池 3.通过xml配置定义线程池 四.异常处理 五.问题 前言 很多业务场景需要使用异步去完成,比如:发送短信通知.要完成异步操作一般有两种: 1.消息队列MQ 2.线程池处理. 我们来看看Spring框架中如何去使用线程池来完成异步操作,以及分析背后的原理. 一. Spring异步线程池的接口类 :TaskExecutor 在Spring4中,

mysql主从同步原理及应用场景示例详解

目录 基础知识 MySQL 主从同步的主要应用场景有: 原理 设置主从同步,还有以下几个前提: 实验环境模拟实现主从同步 首先在 docker 中拉取 mysql 5.7 版本的镜像: 通过以下命令进入到 Master 容器内部: 接下来,进入数据库: 接下来执行以下命令: 基础知识 随着业务复杂度的增加,单台 MySQL 数据库服务器已不能满足实际的需求,取而代之的是数据库服务器集群.MySQL 具有支持分布式的特性,能轻松搭建一个支持高并发的 MySQL 数据库服务器集群.在集群中我们必须保

Java线程之线程同步synchronized和volatile详解

上篇通过一个简单的例子说明了线程安全与不安全,在例子中不安全的情况下输出的结果恰好是逐个递增的(其实是巧合,多运行几次,会产生不同的输出结果),为什么会产生这样的结果呢,因为建立的Count对象是线程共享的,一个线程改变了其成员变量num值,下一个线程正巧读到了修改后的num,所以会递增输出. 要说明线程同步问题首先要说明Java线程的两个特性,可见性和有序性.多个线程之间是不能直接传递数据交互的,它们之间的交互只能通过共享变量来实现.拿上篇博文中的例子来说明,在多个线程之间共享了Count类的

java线程池ThreadPoolExecutor的八种拒绝策略示例详解

目录 池化设计思想 线程池触发拒绝策略的时机 JDK内置4种线程池拒绝策略 拒绝策略接口定义 AbortPolicy(中止策略) DiscardPolicy(丢弃策略) DiscardOldestPolicy(弃老策略) 第三方实现的拒绝策略 Dubbo 中的线程拒绝策略 Netty 中的线程池拒绝策略 ActiveMQ 中的线程池拒绝策略 PinPoint 中的线程池拒绝策略 谈到 Java 的线程池最熟悉的莫过于 ExecutorService 接口了,jdk1.5 新增的 java.uti

Golang WorkerPool线程池并发模式示例详解

目录 正文 处理CVS文件记录 获取测试数据 线程池耗时差异 正文 Worker Pools 线程池是一种并发模式.该模式中维护了固定数量的多个工作器,这些工作器等待着管理者分配可并发执行的任务.该模式避免了短时间任务创建和销毁线程的代价. 在 golang 中,我们使用 goroutine 和 channel 来构建这种模式.工作器 worker 由一个 goroutine 定义,该 goroutine 通过 channel 获取数据. 处理CVS文件记录 接下来让我们通过一个例子,来进一步理

Awaitility同步异步工具实战示例详解

目录 引言 1. awaitility入门 1.1 静态导入 1.2 简单例子 2. awaitility在RocketMQ中的实战 3. 总结 引言 在编写测试用例的时候遇到有异步或者队列处理的时候经常会用到 Thread.sleep() 等待来进行测试.例如:DLedger 测试选举的过程.当DLedger Leader下线.此时DLedger会重新发起选举,这个选举的过程是需要一定时间.很多时候在测试代码中就会使用 Thread.sleep . 由于选举需要的时间多少不确定所以sleep时

Java ExecutorService四种线程池使用详解

1.引言 合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要的等到线程创建就能立即执行.第三:提高线程的可管理性.线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控.但是要做到合理的利用线程池,必须对其原理了如指掌. 2.线程池使用 Executors提供的四种线程 1.newCachedThreadPool创建一个可缓存线程池