【发布时间】:2018-07-31 14:54:38
【问题描述】:
我目前正在尝试多线程创建一个树,其中保存树的类在一大块中预先分配了std::vector 的Nodes特定大小(从概念上讲,大小是任意的)。额外的 Node 块仅在必要时创建,这是因为树很快变得非常大,我想避免经常使用 new 运算符以提高时间效率。
Nodes 的这些向量定义为:std::vector< std::vector< Node > > nodes
head 跟踪内部向量中的位置,chunkCount 跟踪当前正在使用的外部向量。
向量在构造函数中被调整为:
nodes.resize( 1 );
nodes[chunkCount].resize( CHUNK_SIZE );
Node 的简化版本是:
typedef struct Node {
int val;
Node* subnodes[5];
} Node;
创建一个新的Node 如下:
void TreeClass::createNode( Node* node, short index, int val )
{
omp_set_lock( &treeLock ); // treeLock belongs to TreeClass
head++;
if( head == CHUNK_SIZE ) {
std::vector< Node > tempNodeVec( CHUNK_SIZE );
nodes.push_back( tempNodeVec );
chunkCount++;
head = 0;
}
node->subnodes[index] = &( nodes[chunkCount][head] );
omp_unset_lock( &treeLock );
node->subnodes[index]->val = val;
}
这工作得很好。然而我担心的是,在创建节点时除了一个线程之外的所有线程都被阻塞,这种情况经常发生,所以很多时间都被阻塞或锁定/解锁treeLock,因此我希望使这个函数无锁 strong> 但到目前为止我的尝试都失败了。
更改head 和chunkCount 很容易,无需使用#pragma omp atomic(或使用std::atomic< int >s)锁定,但这是确保if( ... ) 语句只执行一次和之前的逻辑任何线程都会继续分配孩子的地址,即确保他们使用正确/更新的chunkCount 和head。
阅读关于无锁算法的一个想法是在Node 中使用std::atomic< Node* > subnodes[5] 并执行CAS 操作,等待正确更新的head 和chunkCnt 但不知道什么是“正确的”,我怎么知道我在等什么?
另一个(天真的)想法是:
int myHead;
if( ++head == CHUNK_SIZE ) {
std::vector< Node > tempNodeVec( CHUNK_SIZE );
nodes.push_back( tempNodeVec );
chunkCount++;
myhead = head = 0;
} else {
myhead = head;
while( head > CHUNK_SIZE )
myHead = ++head;
}
node->subnodes[index] = &( nodes[chunkCount][myHead] );
这个想法是只有一个线程进入if( ... ),直到将head设置为0,其余的将卡在else { ... }中,但我已经可以看到与此相关的许多问题接近。
对此的任何帮助将不胜感激。
【问题讨论】:
标签: c++ multithreading tree openmp lock-free