我在函数中使用std :: deque 来访问元素而不从队列中弹出,因为我在不同的迭代中使用相同的队列。我的解决方案基于粗粒度多线程。现在我想制作细粒度的多线程解决方案。为此,我使用tbb :: concurrent_queue。但是我需要在tbb :: concurrent_queue中运行std :: deque 的等效函数吗?
修改 的 这就是我用std :: deque(粗粒度多线程)实现的方法 请记住,dq是静态队列(即在不同的迭代中多次使用)
vertext_found = true;
std::deque<T> dq;
while ( i < dq->size())
{
EnterCriticalSection(&h);
if( i < dq.size() )
{
v = dq.at(i); // accessing element of queue without popping
i++;
vertext_found = true;
}
LeaveCriticalSection(&h);
if (vertext_found && (i < dq.size()) && v != NULL)
{
**operation on 'v'
vertext_found = false;
}
}
我想用tbb :: concurrent_queue实现相同的结果?
答案 0 :(得分:1)
如果您的算法具有填充队列或使用队列的单独传递,请考虑使用tbb :: concurrent_vector。它有一个可用于填充传递的push_back方法,以及用于消耗传递的at()方法。如果线程竞争消费传递中的pop元素,请考虑使用tbb :: atomic计数器为at()生成索引。
如果填充和消费之间没有这种清晰的分离,使用at()可能会产生比它解决的更多问题,即使它存在,因为它会与消费者竞争。
如果消耗传递只需要并行遍历concurrent_vector,请考虑使用tbb :: parallel_for作为循环。 tbb :: concurrent_vector有一个支持这个习语的range()方法。
void consume( tbb::concurrent_vector<T>& vec ) {
tbb::parallel_for( vec.range(), [&]( const tbb::concurrent_vector<T>::range_type& r ) {
for( auto i=r.begin(); i!=r.end(); ++i ) {
T value = *i;
...process value...;
}
});
}
如果消费传递不能使用tbb:parallel_for,请考虑使用TBB原子计数器来生成索引。将计数器初始化为零并使用++递增计数器。这是一个例子:
tbb::atomic<size_t> head;
tbb::concurrent_vector<T> vec;
bool pop_one( T& result ) { // Try to grab next item from vec
size_t i = head++; // Fetch-and-increment must be single atomic operation
if( i<vec.size() ) {
result = vec[i];
return true;
} else {
return false; // Failed
}
}
通常,此解决方案的可扩展性低于使用tbb :: parallel_for,因为计数器“head”会在内存系统中引入争用点。
答案 1 :(得分:0)
根据TBB站点中的Doxygen文档(TBB Doxy docs),队列中没有操作at
。您可以push
和try_pop
元素{/ 1}}。
如果您使用的是tbb::strict_ppl::concurrent_queue
(早期版本的TBB),则tbb::deprecated::concurrent_queue
和push_if_not_full
操作可用。
在两个队列中,“多个线程可以同时推送和弹出”,如下面的简要部分所述。