▶ 本章介绍了手动实现原子操作。重构了第五章向量点积的过程。核心是通过定义结构Lock及其运算,实现锁定,读写,解锁的过程。

● 章节代码

 #include <stdio.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "cuda.h"
#include "D:\Code\CUDA\book\common\book.h" #define imin(a,b) (a<b?a:b)
#define sum_squares(x) (x*(x+1)*(2*x+1)/6)
#define N 33 * 1024 * 1024
#define THREADSIZE 256
#define BLOCKSIZE imin(32, (N + THREADSIZE - 1) / THREADSIZE) struct Lock
{
int *mutex;
Lock(void)
{
int state = ;
cudaMalloc((void **)&mutex, sizeof(int));
cudaMemcpy(mutex, &state, sizeof(int), cudaMemcpyHostToDevice);
}
~Lock(void)
{
cudaFree(mutex);
}
__device__ void lock(void)
{
while (atomicCAS(mutex, , ) != );
//atomicCAS(a, b, c)将判断变量a是否等于b,
//若相等,则用c的值去替换a,并返回c的值;若不相等,则返回a的值
//函数lock()中,线程不断尝试判断mutex是否为0,
//若为0则改写为1 ,表明“占用”,禁止其他线程进行访问
//若为1则继续尝试判断
}
__device__ void unlock(void)
{
atomicExch(mutex, );
//atomicExch(a, b)返回第一个变量的值,并将两个变量的值进行交换
//这里使用原子操作只是与上面的atomicCAS统一,否则可以直接用赋值语句
//线程操作完成,将mutex改写回0,允许其他线程进行访问
}
}; __global__ void dot(Lock lock, float *a, float *b, float *c)
{
__shared__ float share[THREADSIZE];
int tid = threadIdx.x + blockIdx.x * blockDim.x;
int cacheIndex = threadIdx.x;
float temp = ; while (tid < N)
{
temp += a[tid] * b[tid];
tid += blockDim.x * gridDim.x;
} share[cacheIndex] = temp;
__syncthreads(); int i = blockDim.x / ;
while (i != )
{
if (cacheIndex < i)
share[cacheIndex] += share[cacheIndex + i];
__syncthreads();
i /= ;
}
if (cacheIndex == )
{
lock.lock();// 等待可写入的机会,锁上,写入,再解锁
*c += share[];
lock.unlock();
}
} int main(void)
{
float *a, *b, c = ;
float *dev_a, *dev_b, *dev_c; a = (float*)malloc(N * sizeof(float));
b = (float*)malloc(N * sizeof(float)); cudaMalloc((void**)&dev_a, N * sizeof(float));
cudaMalloc((void**)&dev_b, N * sizeof(float));
cudaMalloc((void**)&dev_c, sizeof(float)); for (int i = ; i < N; i++)
{
a[i] = i;
b[i] = i * ;
} cudaMemcpy(dev_a, a, N * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(dev_b, b, N * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(dev_c, &c, sizeof(float), cudaMemcpyHostToDevice); Lock lock;
dot << <BLOCKSIZE, THREADSIZE >> > (lock, dev_a, dev_b, dev_c); cudaMemcpy(&c, dev_c, sizeof(float), cudaMemcpyDeviceToHost); printf("\n\tAnswer:\t\t%.6g\n\tGPU value:\t%.6g\n", * sum_squares((float)(N - )), c); free(a);
free(b);
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
getchar();
return ;
}

《GPU高性能编程CUDA实战》附录一 高级原子操作的更多相关文章

  1. [问题解决]《GPU高性能编程CUDA实战》中第4章Julia实例“显示器驱动已停止响应,并且已恢复”问题的解决方法

    以下问题的出现及解决都基于"WIN7+CUDA7.5". 问题描述:当我编译运行<GPU高性能编程CUDA实战>中第4章所给Julia实例代码时,出现了显示器闪动的现象 ...

  2. 《GPU高性能编程CUDA实战》附录二 散列表

    ▶ 使用CPU和GPU分别实现散列表 ● CPU方法 #include <stdio.h> #include <time.h> #include "cuda_runt ...

  3. 《GPU高性能编程CUDA实战》附录四 其他头文件

    ▶ cpu_bitmap.h #ifndef __CPU_BITMAP_H__ #define __CPU_BITMAP_H__ #include "gl_helper.h" st ...

  4. 《GPU高性能编程CUDA实战》附录三 关于book.h

    ▶ 本书中用到的公用函数放到了头文件book.h中 #ifndef __BOOK_H__ #define __BOOK_H__ #include <stdio.h> #include &l ...

  5. 《GPU高性能编程CUDA实战》第十一章 多GPU系统的CUDA C

    ▶ 本章介绍了多设备胸膛下的 CUDA 编程,以及一些特殊存储类型对计算速度的影响 ● 显存和零拷贝内存的拷贝与计算对比 #include <stdio.h> #include " ...

  6. 《GPU高性能编程CUDA实战》第五章 线程并行

    ▶ 本章介绍了线程并行,并给出四个例子.长向量加法.波纹效果.点积和显示位图. ● 长向量加法(线程块并行 + 线程并行) #include <stdio.h> #include &quo ...

  7. 《GPU高性能编程CUDA实战》第四章 简单的线程块并行

    ▶ 本章介绍了线程块并行,并给出两个例子:长向量加法和绘制julia集. ● 长向量加法,中规中矩的GPU加法,包含申请内存和显存,赋值,显存传入,计算,显存传出,处理结果,清理内存和显存.用到了 t ...

  8. 《GPU高性能编程CUDA实战》第八章 图形互操作性

    ▶ OpenGL与DirectX,等待填坑. ● basic_interop #include <stdio.h> #include "cuda_runtime.h" ...

  9. 《GPU高性能编程CUDA实战》第七章 纹理内存

    ▶ 本章介绍了纹理内存的使用,并给出了热传导的两个个例子.分别使用了一维和二维纹理单元. ● 热传导(使用一维纹理) #include <stdio.h> #include "c ...

随机推荐

  1. BZOJ4916: 神犇和蒟蒻【杜教筛】

    Description 很久很久以前,有一只神犇叫yzy; 很久很久之后,有一只蒟蒻叫lty; Input 请你读入一个整数N;1<=N<=1E9,A.B模1E9+7; Output 请你 ...

  2. FZU OJ:2230 翻翻棋

    Problem 2230 翻翻棋 Accept: 872    Submit: 2132Time Limit: 1000 mSec    Memory Limit : 32768 KB  Proble ...

  3. 牛客练习赛14A(唯一分解定理)

    https://www.nowcoder.com/acm/contest/82/A 首先这道题是求1~n的最大约数个数的,首先想到使用唯一分解定理,约数个数=(1+e1)*(1+e2)..(1+en) ...

  4. jquery选择器总结2

    1.JQuery的概念 JQuery是一个JavaScript的类库,这个类库集合了很多功能方法,利用类库你可以用一些简单的代码实现一些复杂的JS效果. 2.JQuery实现了 代码的分离 不用再网页 ...

  5. java环境变量 Path 与CLASSPATH

    1.Windows操作系统根据Path环境变量来查找命令,Linux操作系统则根据PATH环境变量来查找命令 因为Windows操作系统不区分大小写,设置Path和PATH并没有区别,而Linux系统 ...

  6. vulcanjs 包类型

    npm 添加在pacakge.json 文件中的 meteor core 包 由meteor 框架提供的 meteor remote 包 从包服务器加载的,使用username:package 格式组 ...

  7. 实现JMS规范的ActiveMQ

    ActiveMQ是Apache软件基金会的开源产品,支持AMQP协议.MQTT协议(和XMPP协议作用类似).Openwire协议和Stomp协议等多种消息协议.并且ActiveMQ完整支持JMS A ...

  8. linux同一客户端多个git账号的配置

    有时候我们需要在同一台机器上使用多个git账号,为了避免冲突,我们需要配置~/.ssh/config文件. 步骤一:用ssh-keygen命令生成一组新的id_rsa_new和id_rsa_new.p ...

  9. android调节音量——AudioManager的应用

    Android中可以通过程序获取系统手机的铃声和音量.同样,也可以设置铃声和音量.android中给出了AudioManager类来实现音量获取.音量控制. 本篇基于 Android API 中的 A ...

  10. 虚拟机设置成桥接模式x86_openwrt也可以上网

    一.虚拟机桥接设置 1. 2.选择 虚拟机 >>设置 三.ip设置,要在同一网段,能够分配到路由的ip地址 1.主机ip 2.虚拟机中x86_openwrt ip 四.openwrt设置 ...