zoukankan      html  css  js  c++  java
  • CUDA线程协作之共享存储器“__shared__”&&“__syncthreads()”

    在GPU并行编程中,一般情况下,各个处理器都需要了解其他处理器的执行状态,在各个并行副本之间进行通信和协作,这涉及到不同线程间的通信机制和并行执行线程的同步机制。

    共享内存“__share__”


    CUDA中的线程协作主要是通过共享内存实现的。使用关键字“__share__”声明共享变量,将使这个变量驻留在共享内存中,该变量具有以下特征:

    • 位于线程块的共享存储器空间中
    • 与线程块具有相同的生命周期
    • 仅可通过块内的所有线程访问

    对于GPU上启动的每个线程块,CUDA C编译器都将创建该变量的一个副本。 线程块中的每个线程都共享这块内存,但线程却无法看到也不能修改其他线程块的变量副本。 这就使得一个线程块中的多个线程能够在计算上进行通信和协作。而且,共享内存缓冲区驻留在物理GPU上,在访问共享内存时的延迟要远远低于访问普通缓冲区的延迟,使得共享内存的访问非常高效。

    线程同步机制“__syncthreads()”


    关键字“__share__”只是声明了共享变量,位于同一个线程块中的不同线程都可以访问该变量,如果没有同步机制,将会发生竞态条件 (Race Condition),导致错误的运行结果。
    CUDA确保同步的方法是调用“__syncthreads()”。__syncthreads()将确保线程块中的每个线程都执行完 __syncthreads()前面的语句后,才会执行下一条语句。

    以下是CUDA和OpenCV的应用中,绘制一幅图像,Grid的尺寸大小是60*60,Block的尺寸大小是10*10,在各个线程块内声明了一个共享变量sharedMem:

    #include "cuda_runtime.h"    
    #include <highgui.hpp>    
    
    using namespace cv;
    
    #define DIM 600   //图像长宽
    #define PI 3.1415926535897932f  
    
    __global__ void kernel(unsigned char *ptr)
    {
    	// map from blockIdx to pixel position    
    	int x = threadIdx.x + blockIdx.x * blockDim.x;
    	int y = threadIdx.y + blockIdx.y * blockDim.y;
    	int offset = x + y * blockDim.x * gridDim.x;
    
    	__shared__  float sharedMem[16][16];
    	const float period = 128.0f;
    	sharedMem[threadIdx.x][threadIdx.y] =
    		255 * (sinf(x*2.0f*PI / period) + 1.0f) *
    		(sinf(y*2.0f*PI / period) + 1.0f) / 4.0f;
    	__syncthreads();
    
    	ptr[offset * 3 + 0] = 0;
    	ptr[offset * 3 + 1] = sharedMem[15 - threadIdx.x][15 - threadIdx.y];
    	ptr[offset * 3 + 2] = 0;
    }
    
    // globals needed by the update routine    
    struct DataBlock
    {
    	unsigned char   *dev_bitmap;
    };
    
    int main(void)
    {
    	DataBlock   data;
    	cudaError_t error;
    
    	Mat image = Mat(DIM, DIM, CV_8UC3, Scalar::all(0));
    
    	data.dev_bitmap = image.data;
    	unsigned char    *dev_bitmap;
    
    	error = cudaMalloc((void**)&dev_bitmap, 3 * image.cols*image.rows);
    	data.dev_bitmap = dev_bitmap;
    
    	dim3    grid(DIM / 10, DIM / 10);
    	dim3   block(10, 10);
    	//DIM*DIM个线程块  
    	kernel << <grid, block >> > (dev_bitmap);
    
    	error = cudaMemcpy(image.data, dev_bitmap,
    		3 * image.cols*image.rows,
    		cudaMemcpyDeviceToHost);
    
    	error = cudaFree(dev_bitmap);
    
    	imshow("__share__ and __syncthreads()", image);
    	waitKey();
    }


    如果线程间不加入__syncthreads()同步机制,同一线程块内不同线程访问sharedMem,获取的结果可能是不一样的,生成的图像如下,有散乱的杂点:


    加入__syncthreads()同步机制保证了同一线程块中不同的线程都执行完成__syncthreads()这个集合点之前的部分之后,才继续往下执行,所以不同的线程访问sharedMem获取的结果是一致的,图像无杂散点,是一个规律的排布:


  • 相关阅读:
    metadata
    java.net.SocketException: Permission denied 连网权限
    JUnit4 测试
    web生成工具
    Linux scp 两台服务器传输文件
    eclipse 无法导入项目
    html 流动字幕 marquee 标签 jquery
    libSVM 简易入门
    程序员创业指导书
    svm(libsvm)在文本分类中的应用
  • 原文地址:https://www.cnblogs.com/mtcnn/p/9411870.html
Copyright © 2011-2022 走看看