CUDA动态并行与全局内存同步

CUDA动态并行与全局内存同步,cuda,Cuda,我想不出以下几点 如果我启动一个内核,例如在代码< >代码> 0 中考虑线程 0代码/代码>,在代码< > ySythththRead()>代码>调用之后,所有其他块中的所有其他线程都会看到在代码< > 0 < /COD> < /P>中,线程 0 < /代码>对全局内存所做的更改吗? 我的猜测是否定的。事实上,在《CUDA C编程指南》的一节中,它指出: void\uuuu syncthreads() 等待线程块中的所有线程都达到此点,并且块中的所有线程都可以看到这些线程在\uu syncthr

我想不出以下几点

如果我启动一个内核,例如在代码< >代码> 0 <代码>中考虑线程<代码> 0代码/代码>,在代码< > ySythththRead()>代码>调用之后,所有其他块中的所有其他线程都会看到在代码< > 0 < /COD> < /P>中,线程<代码> 0 < /代码>对全局内存所做的更改吗? 我的猜测是否定的。事实上,在《CUDA C编程指南》的一节中,它指出:

void\uuuu syncthreads()
等待线程块中的所有线程都达到此点,并且块中的所有线程都可以看到这些线程在
\uu syncthreads()
之前进行的所有全局和共享内存访问

但是,在谈到动态并行时,《CUDA C编程指南》指出:

只有在第二次调用
\uuu syncthreads()
后,这些修改才会对父网格的其他线程可用

当涉及到动态并行性时,
\uuu syncthreads()
是否也可以跨块进行更改


谢谢

\uu syncthreads()
执行的唯一操作是您自己在CUDA C编程指南中引用的操作。在CUDA中,除了将一个内核的执行划分为多个内核启动的幼稚方法之外,没有任何方法可以跨块同步,但在性能方面存在所有缺点。因此,你的第一个问题的答案,正如你自己猜测的,是否定的

在文章的第二部分中,您提到了CUDAC编程指南的一个具体示例,即

__global__ void child_launch(int *data) {
    data[threadIdx.x] = data[threadIdx.x]+1;
}

__global__ void parent_launch(int *data) { 
    data[threadIdx.x] = threadIdx.x;

    __syncthreads();

    if (threadIdx.x == 0) {
        child_launch<<< 1, 256 >>>(data);
        cudaDeviceSynchronize();
    }

    __syncthreads();
}

void host_launch(int *data) {
    parent_launch<<< 1, 256 >>>(data);
}
\uuuuu全局\uuuuu无效子项\u启动(int*数据){
数据[threadIdx.x]=数据[threadIdx.x]+1;
}
__全局\uuuuuu无效父\u启动(int*数据){
数据[threadIdx.x]=threadIdx.x;
__同步线程();
if(threadIdx.x==0){
儿童启动>(数据);
cudaDeviceSynchronize();
}
__同步线程();
}
无效主机启动(int*数据){
母公司发布>(数据);
}
在这里,
parent\u-launch
内核的所有
256
线程都在
数据中写入内容。之后,线程
0
调用
child\u launch
。需要第一个
\uuu syncthreads()
,以确保在子内核调用之前完成所有内存写入。引用关于这一点的指南:

由于第一个
\u syncthreads()
调用,子级将看到
数据[0]=0
数据[1]=1
,…,
数据[255]=255
(如果没有
\u syncthreads()
调用,子级将保证只看到
数据[0]

关于第二个
\uuu syncthreads()
,本指南解释如下:

当子网格返回时,线程
0
保证看到子网格中的线程所做的修改。只有在第二次调用
\uuu syncthreads()
后,这些修改才会对父网格的其他线程可用

在该特定示例中,第二个
\uuuuu syncthreads()
是冗余的,因为内核终止会导致隐式同步,但在子内核启动后必须执行其他操作时,则需要第二个
\uuu syncthreads()

最后,关于你在帖子中引用的句子:

只有在第二次调用
\uuu syncthreads()
后,这些修改才会对父网格的其他线程可用

请注意,在特定示例中,
host\u launch
函数只启动了一个线程块。这也许有点误导了你

在英伟达论坛上,有一个有趣的讨论(可能不止一次),该论坛的标题是“

”的线程同步。
\uuu syncthreads()
执行的唯一操作是您自己在CUDA C编程指南中引用的操作。在CUDA中,除了将一个内核的执行划分为多个内核启动的幼稚方法之外,没有任何方法可以跨块同步,但在性能方面存在所有缺点。因此,你的第一个问题的答案,正如你自己猜测的,是否定的

在文章的第二部分中,您提到了CUDAC编程指南的一个具体示例,即

__global__ void child_launch(int *data) {
    data[threadIdx.x] = data[threadIdx.x]+1;
}

__global__ void parent_launch(int *data) { 
    data[threadIdx.x] = threadIdx.x;

    __syncthreads();

    if (threadIdx.x == 0) {
        child_launch<<< 1, 256 >>>(data);
        cudaDeviceSynchronize();
    }

    __syncthreads();
}

void host_launch(int *data) {
    parent_launch<<< 1, 256 >>>(data);
}
\uuuuu全局\uuuuu无效子项\u启动(int*数据){
数据[threadIdx.x]=数据[threadIdx.x]+1;
}
__全局\uuuuuu无效父\u启动(int*数据){
数据[threadIdx.x]=threadIdx.x;
__同步线程();
if(threadIdx.x==0){
儿童启动>(数据);
cudaDeviceSynchronize();
}
__同步线程();
}
无效主机启动(int*数据){
母公司发布>(数据);
}
在这里,
parent\u-launch
内核的所有
256
线程都在
数据中写入内容。之后,线程
0
调用
child\u launch
。需要第一个
\uuu syncthreads()
,以确保在子内核调用之前完成所有内存写入。引用关于这一点的指南:

由于第一个
\u syncthreads()
调用,子级将看到
数据[0]=0
数据[1]=1
,…,
数据[255]=255
(如果没有
\u syncthreads()
调用,子级将保证只看到
数据[0]

关于第二个
\uuu syncthreads()
,本指南解释如下:

当子网格返回时,线程
0
保证看到子网格中的线程所做的修改。只有在第二次调用
\uuu syncthreads()
后,这些修改才会对父网格的其他线程可用

在该特定示例中,第二个
\uuuu syncthreads()
是冗余的,因为由于内核终止而存在隐式同步,但是第二个
\uuu syncthreads()
变为nee