我正在尝试TBB的英特尔图表流程。我对结果非常满意,我发现产品令人惊叹,具有无限的可能性。然而,我遇到了一个我修复的pb,但我并不满意。 pb如下。
message
A ----------\ tuple<message,message> WHATEVER
message join ------------------------- C------------------------
B ----------/
当我们想要同步并避免传播 n 次消息(及其值)时,将应用此模式。英特尔提供了一个例子,它解释了pb(以及解决方案 - Intel example)。我的pb是构造的tupple和使用静态方法的图的构造。它是完全静态的,特别是如果连接节点的输入边缘({1}}的数量)是变量。
TBB图流的大师是否知道一种动态方法&#34;这个pb?
最佳,
添 [编辑我的代码真实的pb]
我能做到:
input_port<i>
我做不到:
std::vector<tbb::flow::function_node<std::size_t, message>> vec_node;
for (int i(0) ; i < 3 ;++i)
nodes_cont_.emplace_back(my_amazing_function_to_create_node(g_));
tbb::flow::make_edge(vec_node[0], tbb::flow::input_port<0>
tbb::flow::make_edge(vec_node[1], tbb::flow::input_port<1>(node_join_));
tbb::flow::make_edge(vec_node[2], tbb::flow::input_port<2>(node_join_));
由于&#34;元组&#34;和&#34; tbb :: flow :: input_port&#34;功能。
答案 0 :(得分:3)
join
节点上的端口数是静态的(在编译时确定。)如果要为一个输出提供变量数量的输入,则需要能够指示哪个&#34;端口&# 34;消息传来,以及它的价值。
TBB有一种变体类型,它封装了端口号和值(它是indexer_node
的输出。)如果您使用该类型(定义{{1}},但不要实例化它,你可以使用节点的indexer_node
作为::output_type
的输入类型(它可能有多个输出,但只能有一个输出),并让函数multifunction_node
的主体决定何时输出正确数量,然后您可以在输入时存储值,并在multifunction_node
看到&#34;正确&#34;输入数量,它可以构造一个输出值并将其转发给它的后继者。
图表如下:
我看到的一个问题是您必须定义multifunction_node
的输出类型。这也是一个静态声明,尽管变量元组可能就是你所需要的。
编辑:
让我们做一些简化的假设:
multifunction_node
,但它在运行时是已知且不变的。放宽此约束将需要为每条消息传递一些额外的数据。N
,但我认为这是因为tuple
的输出是join_nodes
(我试图添加向量作为一个特例,但我不是&#39} ; t认为这是一个选项。)我假设你在向量中的所有tuple
都与输出具有相同的类型。这样我们就可以避免使用变体类型。function_nodes
,那么该缓冲区的地址就是让我们知道哪些消息放在一起的部分。我在TBB工作已经有几年了,所以可能会有一些我不知道的事情,但我可以给你一个草图。
图表如下:
(我实际上勾勒出了标签匹配连接的结构,因为它听起来就像你想要的那样。)
构造function_node
的向量时,每个function_nodes
都必须知道它的索引是什么。通常,这意味着向量是指向function_body
的指针,并且每个节点都以索引作为其参数之一构建。
我假设function_nodes
输出类似于缓冲区。该缓冲区传递给向量中的每个source_node's
,每个function_node
的输出类型为
function_node
的索引 function_node
是完成大部分工作的地方。它有
multifuncton_node
的向量,由hash_maps
索引索引,并带有缓冲区地址的键,包含各种缓冲区的每个function_node
的结果。function_node
,包含为该缓冲区接收的nuber元素的计数。当它达到N时,你有所有的输入。当hash_map
收到消息时,
multifunction_node
,其中i是hash_map[i][key]
索引(在输入消息中),key是缓冲区地址function_node
。如果现在是hash_count[key]
,那么对于如何传递和存储数据存在一些问题,以及如果希望重复使用值,如何清理元素,但这是基本草图。
答案 1 :(得分:0)
如果您在编译时为特定程序知道N,但是想要以通用方式实现图形以供在不同程序中使用的库,则BOOST_PP是小N的选项。
我实现了一个图,该图在连接最慢的节点输出continue_msg之后生成continue_msg。为此,我需要多个N缓冲节点,并将它们连接到具有N个相同类型(tbb :: flow :: continue_msg)端口的连接节点。
基本上,以下代码可以实现您想要的
for(int i(0); i < vec_node.size(); ++i)
tbb::flow::make_edge(vec_node[i], tbb::flow::input_port<i>(node_join_));
...但是使用预编译器通过正确的make_edge调用“写”多行,但最多不超过N(对于N 此代码是函数定义。然后可以调用“ makeAllEdges”。 (请注意,在此示例中,我假设makeAllEdges是一个类方法,而vec_node是该类的成员,并且在makeAllEdges的场景中也是如此。) #include "boost/preprocessor/repetition/repeat_from_to.hpp"
#include "boost/preprocessor/repetition/repeat.hpp"
#include "boost/preprocessor/arithmetic/inc.hpp"
...
#define MY_JOIN_NODE_VARIADIC_MAX 8
#define MY_FUNC_IMPL(z, n, unused) tbb::flow::make_edge(vec_node[##n], tbb::flow::input_port<##n>(joinNode));
#define MY_MAKE_IMPL(z, n, unused) \
template <size_t N, typename TJoinNode> void \
makeAllEdges (TJoinNode& joinNode, \
typename std::enable_if< N == n >::type * = 0) \
{ \
BOOST_PP_REPEAT(n, MY_FUNC_IMPL, unused) \
}
BOOST_PP_REPEAT_FROM_TO(0, BOOST_PP_INC(MY_JOIN_NODE_VARIADIC_MAX), MY_MAKE_IMPL, unused)
#undef MY_MAKE_IMPL
#undef MY_FUNC_IMPL
#undef MY_JOIN_NODE_VARIADIC_MAX