Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading &引用;螺纹组“U型屏障”;没有区别_Multithreading_Gpu_Metal_Compute Shader_Threadgroup - Fatal编程技术网

Multithreading &引用;螺纹组“U型屏障”;没有区别

Multithreading &引用;螺纹组“U型屏障”;没有区别,multithreading,gpu,metal,compute-shader,threadgroup,Multithreading,Gpu,Metal,Compute Shader,Threadgroup,目前,我正在使用金属计算着色器,并试图了解GPU线程同步在那里是如何工作的 我编写了一个简单的代码,但它的工作方式与我预期的不同: 假设我有threadgroup变量,它是一个数组,所有线程都可以在其中同时生成一个输出 kernel void compute_features(device float output [[ buffer(0) ]], ushort2 group_pos [[ threadgroup_posi

目前,我正在使用金属计算着色器,并试图了解GPU线程同步在那里是如何工作的

我编写了一个简单的代码,但它的工作方式与我预期的不同:

假设我有
threadgroup
变量,它是一个数组,所有线程都可以在其中同时生成一个输出

    kernel void compute_features(device float output [[ buffer(0) ]],
                                 ushort2 group_pos [[ threadgroup_position_in_grid ]],
                                 ushort2 thread_pos [[ thread_position_in_threadgroup]],
                                 ushort tid [[ thread_index_in_threadgroup ]])
    {     
        threadgroup short blockIndices[288];

        float someValue = 0.0
        // doing some work here which fills someValue...

        blockIndices[thread_pos.y * THREAD_COUNT_X + thread_pos.x] = someValue;

        //wait when all threads are done with calculations
        threadgroup_barrier(mem_flags::mem_none);  
        output += blockIndices[thread_pos.y * THREAD_COUNT_X + thread_pos.x]; // filling out output variable with threads calculations
    }
上面的代码不起作用。输出变量不包含所有线程的计算,它只包含上一次在将值添加到
输出时假定的来自线程的值。在我看来,
threadgroup\u barrier
似乎什么都不做

现在,有趣的部分。以下代码有效:

blockIndices[thread_pos.y * THREAD_COUNT_X + thread_pos.x] = someValue;

threadgroup_barrier(mem_flags::mem_none);  //wait when all threads are done with calculations
if (tid == 0) {
    for (int i = 0; i < 288; i ++) {
        output += blockIndices[i]; // filling out output variable with threads calculations
    }
}
blockindex[thread_pos.y*thread_COUNT_X+thread_pos.X]=someValue;
threadgroup_屏障(mem_标志::mem_无)//等待所有线程完成计算
如果(tid==0){
对于(int i=0;i<288;i++){
output+=blockindex[i];//使用线程计算填充输出变量
}
}
此代码也与前一个代码一样有效:

blockIndices[thread_pos.y * THREAD_COUNT_X + thread_pos.x] = someValue;

if (tid == 0) {
    for (int i = 0; i < 288; i ++) {
        output += blockIndices[i]; // filling out output variable with threads calculations
    }
}
blockindex[thread_pos.y*thread_COUNT_X+thread_pos.X]=someValue;
如果(tid==0){
对于(int i=0;i<288;i++){
output+=blockindex[i];//使用线程计算填充输出变量
}
}
总而言之:只有当我在一个GPU线程中处理线程组内存时,我的代码才能按预期工作,不管它的id是什么,它可以是线程组中的最后一个线程,也可以是第一个线程。而
threadgroup\u屏障的存在绝对没有区别。我还使用了
threadgroup\u barrier
mem\u threadgroup
标志,代码仍然不起作用


我知道我可能遗漏了一些非常重要的细节,如果有人能指出我的错误,我会很高兴。提前谢谢

当您编写
output+=blockindex[…]
时,所有线程都将尝试同时执行此操作。但由于
output
不是一个原子变量,这会导致竞争条件。这不是线程安全操作


您的第二个解决方案是正确的。您只需要一个线程来收集结果(尽管您也可以将其拆分为多个线程)。如果你移除了障碍物,它仍然可以正常工作,这可能是运气使然。

谢谢你的回复!你的回答对我来说很有意义,谢谢你帮我清理了脑子里的烂摊子。顺便说一句,我尝试将数据保存拆分为两个线程,似乎它可以工作。但是,如果我试图超越这一点,我开始遇到一些随机问题。一个典型的解决方案是288/2=144个线程,每个线程加上两个值。然后添加一个线程组屏障。接下来,使用144/2=72个线程,每个线程将两个值相加。接下来是线程组屏障,接下来是72/2=36个线程。等等这比让一个线程做所有的总结更有效,但是你需要确保到处都有障碍。