Cuda 是否同步网格中的所有线程?

Cuda 是否同步网格中的所有线程?,cuda,Cuda,…还是仅当前扭曲或块中的线程 另外,当特定块中的线程(在内核中)遇到以下行 __shared__ float srdMem[128]; 他们会只声明这个空间一次吗(每个块) 它们显然都是异步运行的,因此如果块22中的线程23是第一个到达此行的线程,而块22中的线程69是最后一个到达此行的线程,那么线程69将知道它已经被声明了?\u syncthreads()等待,直到同一块中的所有线程都已到达该命令,并且扭曲中的所有线程都已到达该语句-这意味着属于threadblock的所有扭曲都必须到达该

…还是仅当前扭曲或块中的线程

另外,当特定块中的线程(在内核中)遇到以下行

__shared__  float srdMem[128];
他们会只声明这个空间一次吗(每个块)

它们显然都是异步运行的,因此如果块22中的线程23是第一个到达此行的线程,而块22中的线程69是最后一个到达此行的线程,那么线程69将知道它已经被声明了?

\u syncthreads()
等待,直到同一块中的所有线程都已到达该命令,并且扭曲中的所有线程都已到达该语句-这意味着属于threadblock的所有扭曲都必须到达该语句

如果在内核中声明共享内存,则该数组将仅对一个线程块可见。因此,每个块都有自己的共享内存块。

syncthreads()命令是块级的同步屏障。这意味着,当一个区块中的所有螺纹都达到屏障时,可以安全使用。也可以在条件代码中使用
\u syncthreads()
,但只有当所有线程对此类代码求值相同时,否则执行可能会挂起或产生意外的副作用

使用
\uuu syncthreads()
的示例:()

要同步网格中的所有线程,当前存在而不是本机API调用。在网格级别同步线程的一种方法是使用连续的内核调用,因为此时所有线程都从同一点结束并重新开始。它通常也称为CPU同步或隐式同步。因此,它们都是同步的

使用此技术()的示例:


关于第二个问题,它会声明每个块指定的共享内存量。考虑到可用共享内存的数量是按SM测量的。因此,我们应该非常小心如何将共享内存启动配置一起使用我同意这里的所有答案,但我认为我们在这里遗漏了一个重要的点w.r.t第一个问题。我不回答第二个答案,因为上面的答案回答得很好

GPU上的执行以扭曲为单位。warp是一组32个线程,特定warp的每个线程在同一时间执行相同的指令。如果在一个块中分配128个线程,那么GPU将有(128/32=)4个扭曲

现在问题变成了“如果所有线程都在执行相同的指令,那么为什么需要同步?”。答案是我们需要同步属于同一块的扭曲__syncthreads不会同步扭曲中的线程,它们已同步。它同步属于同一块的扭曲

这就是为什么您的问题的答案是:uu syncthreads不会同步网格中的所有线程,而是属于一个块的线程,因为每个块都独立执行


如果您想同步一个网格,那么将内核(K)分成两个内核(K1和K2),并调用这两个内核。它们将被同步(K1完成后将执行K2)。

现有的答案在回答
\uu syncthreads()
如何工作方面做得很好(它允许块内同步),我只想添加一个更新,即现在有更新的块间同步方法。自CUDA 9.0以来,引入了“协作组”,允许同步整个块网格(如中所述)。这实现了与启动新内核(如上所述)相同的功能,但通常可以以较低的开销实现,并使代码更具可读性。

为了提供更多详细信息,除了答案外,还引用:

更一般地说,_syncthreads()是一种屏障原语,旨在保护您免受块内的读后写内存争用情况的影响

使用规则非常简单:

  • 当一个线程可能读取另一个线程已写入的内存位置时,在写入之后和读取之前放置一个_syncthreads()

  • __syncthreads()只是块中的一个屏障,因此它无法保护您免受全局内存中的读后写竞争条件的影响,除非同一块中的线程之间存在唯一可能的冲突__syncthreads()通常用于保护写入后读取的共享内存

  • 在确定每个线程都将到达相同的uu syncthreads()调用之前,不要在分支或循环中使用u syncthreads()调用。这有时可能需要将if块分成几块,以便在顶层放置_syncthread()调用,所有线程(包括那些没有通过if谓词的线程)都将执行这些调用

  • 在循环中查找先读后写的情况时,在确定将_syncthread()调用放在何处时,在脑海中展开循环会有所帮助。例如,如果在循环中有来自不同线程对同一共享内存位置的读写,则通常需要在循环结束时额外调用_syncthreads()

  • __syncthreads()不标记关键部分,因此不要这样使用它

  • 不要在内核调用的末尾放一个_syncthreads()。没有必要

  • 许多内核根本不需要_syncthreads(),因为两个不同的线程从不访问同一个内存位置


  • 共享内存分别分配给每个块,但不是同时分配。当SM实际开始执行该块时,共享内存在那个时候被分配。这实际上不是真的。
    shared
    数组被分配给设备中的每个块。@KiaMorot:我想你误解了什么。没有什么可抱怨的
    __global__ void globFunction(int *arr, int N) 
    {
        __shared__ int local_array[THREADS_PER_BLOCK];  //local block memory cache           
        int idx = blockIdx.x* blockDim.x+ threadIdx.x;
    
        //...calculate results
        local_array[threadIdx.x] = results;
    
        //synchronize the local threads writing to the local memory cache
        __syncthreads();
    
        // read the results of another thread in the current thread
        int val = local_array[(threadIdx.x + 1) % THREADS_PER_BLOCK];
    
        //write back the value to global memory
        arr[idx] = val;        
    }