我正在glsl的缓冲区内部构建树结构。
树中的每个节点都有8个整数,这些整数确定数组中该节点的8个子节点的位置。
例如:
tree[0].children = [1,5,3,9,100000,7,100,10]
tree[1].children = [2,3,4,900,8,11,20,13]
潜在的可能结果。
单个线程“分配”内存的方式是。缓冲区有一个全局索引,初始化为0。
当前线程检查当前节点的子节点之一是否为0,如果是,则将索引增加1,并将子节点的值设置为index的先前值。
换句话说:
if(tree[node].children[current_child] == 0) {
tree[node].children[current_child] = tree_index++;
}
这显然会造成一些糟糕的竞争条件,因为执行上述操作时,子线程的值和索引可能会被其他线程更改。
我对这个问题的解决方案是创建一个忙循环互斥体,以锁定所有试图在一个线程分配子节点时修改该子节点的线程。看起来像这样:
int mrun = 100;
while ((tree[0].children[child] <= 0) && (mrun > 0))
{
mrun--;
//If the node wasn't allocated, allocate its memory (which also releases the lock)
if( (atomicCompSwap( tree[0].children[child] , 0 , -1) == 0 ))
{
tree[0].children[child] = int(atomicAdd(t_index, 1));
}
}
这有效,但有多个警告。首先,while循环可能会运行过多,因此我必须限制其执行的次数,这会导致某些值的丢失(存在多个重复的值,因此多数情况下很好)。这也迫使我浪费计算周期,等待和检查。最后,着色器中的while循环并不完全理想。
我尝试通过以下方法解决此问题:
atomicCompSwap(tree[0].children[child], 0, atomicAdd(t_index, 1));
但是,这并没有达到预期的效果,这些操作不是同时原子运行的,因此我最终分配错误。
有没有办法可以更有效地进行此分配?也许是多次通过?