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 
#include 
#include 
#include 
void accumulate(boost::promise &p)
{
  int sum = 0;
  for (int i = 0; i < 5; ++i)
    sum += i;
  p.set_value(sum);
}
int main()
{
  boost::promise p;
  boost::future 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 
#include 
#include 
#include 
int accumulate()
{
  int sum = 0;
  for (int i = 0; i < 5; ++i)
    sum += i;
  return sum;
}
int main()
{
  boost::packaged_task task{accumulate};
  boost::future 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 
#include 
#include 
int accumulate()
{
  int sum = 0;
  for (int i = 0; i < 5; ++i)
    sum += i;
  return sum;
}
int main()
{
  boost::future 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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(C++ Futures与Promises线程使用示例讲解)