【BOOST C++ 13 并行编程】(4) Futures和 Promises线程
admin
2024-04-09 12:33:06

一、说明

        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';
}

Example 44.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';
}

Example 44.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,程序将终止。

相关内容

热门资讯

中国六大天花板羊肉汤!各地招牌... 在中国美食版图里,一碗热气腾腾的羊肉汤,是跨越南北的冬日治愈美味。它不止是抚慰味蕾的烟火佳肴,更是扎...
茗聚泉城创新出圈 莒南茶企新品... 茶香汇泉城,创新焕新韵。5月29日,第二十届中国(济南)国际茶产业博览会暨第十四届茶文化节在济南茶叶...
荔枝泡酒怎么泡?内行人教你一步... 荔枝泡酒,作为一种既能满足味蕾又兼具仪式感的果酒制作方式,近年来备受关注。尤其是夏季荔枝大量上市,用...
原创 夏... 步入炎炎夏日,气温一天比一天高,很多长辈朋友都会出现吃不下饭、饭菜没滋味的情况。闷热天气里,油腻的大...