我有以下内核:

__global__
void collect_boundary(const int64_t* cvert, const csr_node* neighb, const bool* affected, int64_t* parent, const uint64_t* dist, uint64_t* ndist, bool* mask, int64_t numvertices){
    int64_t tid = blockIdx.x*blockDim.x + threadIdx.x;
    if(tid >= numvertices || affected[tid] || dist[tid]==MY_INFINITY)
        return;
    for(int64_t index = cvert[tid]; index<cvert[tid+1]; index++){
        auto vtex = neighb[index];
        if(affected[vtex.head]){
            int64_t ndistent = dist[tid] + vtex.weight;
            atomicMin((unsigned long long int*)(ndist + vtex.head),(unsigned long long int)ndistent);
            /*if(ndist[vtex.head] == ndistent){
                parent[vtex.head] = tid;
            }*/
        }
    }
}


基本上,我希望每个线程都按给定的方式计算ndistent,并将ndist [vtex.head]更新为所有ndistents中的最小值。

我使用以下方法实现了此目的:

atomicMin((unsigned long long int*)(ndist + vtex.head),(unsigned long long int)ndistent);

//That is each thread will update ndist[vtex.head] if and only if
//it's own value of ndistent is less than the ndist[vtex.head]
//which was initialized to INFINITY before the kernel launch


但是现在我想存储给出最小ndistent的提示。

我尝试过这样的事情

if(ndist[vtex.head] == ndistent){  // prob_condition 1
    parent[vtex.head] = tid;       // prob_statment 1
}

//That is each thread will check wether the value in
//ndist[vtex.head] is equal to it's own ndistent
// and then store the tid if it is.


上面的代码片段不起作用,因为某些线程X可能会发现prob_condition 1为true,但是在执行prob_statement 1之前,让我们说要赋予最小值的线程说线程Y执行prob_statement 1并存储其tid。现在线程X将恢复并存储它的tid,因此min tid丢失了。

所以我希望prob_condition 1和prob_statement 1被原子执行。

或者,我需要自动执行以下3种操作:


检查ndistent 更新ndist [vtex.head]
将tid存储在parent [vtex.head]中


任何人有任何建议我该怎么做?

编辑:
请注意,我将必须使用可变数量的块和可变数量的线程来运行此内核。

最佳答案

它可能无法按您预期的方式解决并发问题,但是您可以采用两个阶段的方法:首先计算最小值,然后找到具有该最小值的人员。

同样,如果多个tid具有相同的ndistent值,则输出可能会因一次执行而异,实际上,正如Taro所指出的那样,扭曲的执行顺序不遵循可预测的规则。这两个阶段的方法可以帮助您为最小值列表建立可预测的模式。

在一种更狡猾的方法中,如果ndistent值和tid都可以容纳64位,则可以尝试让64bits值的高阶位输入ndistent和低阶位来保存tid,然后在一条指令中执行atomicMin。

09-20 06:01