▶ 包括带有 CL_MEM_READ_ONLY,CL_MEM_WRITE_ONLY,CL_MEM_READ_WRITE 标识的显示拷贝(函数 clEnqueueWriteBuffer 和 clEnqueueReadBuffer);带有 CL_MEM_COPY_HOST_PTR 标识的隐式拷贝(不用拷贝函数,在设备上直接使用);以及使用函数 clEnqueueMapBuffer 直接在设备和主机之间映射(转换)一段内存的指针

● 代码

 #include <cl.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <iostream> using namespace std;
const int nElement = ; const char *programSource = " \
__kernel void vectorAdd(__global int *A, __global int *B, __global int *C) \
{ \
int idx = get_global_id(); \
C[idx] = A[idx] + B[idx]; \
return; \
} \
"; int main(int argc, char* argv[])
{
const size_t dataSize = sizeof(int) * nElement;
int i, *A, *B, *C, *returnC; A = (int *)malloc(dataSize);
B = (int *)malloc(dataSize);
C = (int *)malloc(dataSize);
for (srand((unsigned)time(NULL)), i = ; i < nElement; A[i] = rand() % , B[i] = rand() % , C[i] = A[i] + B[i], i++); cl_int status;
cl_platform_id platform;
clGetPlatformIDs(, &platform, NULL);
cl_device_id device;
clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, , &device, NULL);
cl_context context = clCreateContext(NULL, , &device, NULL, NULL, &status);
cl_command_queue queue = clCreateCommandQueue(context, device, , &status);
cl_program program = clCreateProgramWithSource(context, , &programSource, NULL, &status);
clBuildProgram(program, , &device, NULL, NULL, NULL);
cl_kernel kernel = clCreateKernel(program, "vectorAdd", NULL);
cl_event writeEvent, runEvent, mapEvent; //创建三个内存对象,把 A 隐式拷贝到 clA,把 B 显示拷贝到 clB,clC 接收计算结果映射给 returnC
cl_mem clA = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, dataSize, A, NULL);
cl_mem clB = clCreateBuffer(context, CL_MEM_READ_ONLY, dataSize, NULL, NULL);
cl_mem clC = clCreateBuffer(context, CL_MEM_WRITE_ONLY, dataSize, NULL, NULL); clEnqueueWriteBuffer(queue, clB, , , dataSize, B, , , &writeEvent); clFlush(queue);// 出现需要等待的事件之前,把队列中的任务全部提交掉
clWaitForEvents(, &writeEvent);// 等待指定事件完成 // 执行内核
size_t global_work_size = nElement;
clSetKernelArg(kernel, , sizeof(cl_mem), (void*)&clA);
clSetKernelArg(kernel, , sizeof(cl_mem), (void*)&clB);
clSetKernelArg(kernel, , sizeof(cl_mem), (void*)&clC);
clEnqueueNDRangeKernel(queue, kernel, , NULL, &global_work_size, NULL, , NULL, &runEvent);
clFlush(queue);
clWaitForEvents(, &runEvent); // 结果拷回
returnC = (cl_int *)clEnqueueMapBuffer(queue, clC, CL_TRUE, CL_MAP_READ, , dataSize, , NULL, &mapEvent, NULL);
clFlush(queue);
clWaitForEvents(, &mapEvent); //结果验证
printf("Verify %s.\n", !memcmp(C, returnC, dataSize) ? "passed" : "failed");// 定义在 iostream free(C);
free(A);
free(B);
clReleaseMemObject(clA);
clReleaseMemObject(clB);
clReleaseMemObject(clC);
clReleaseContext(context);
clReleaseCommandQueue(queue);
clReleaseProgram(program);
clReleaseEvent(writeEvent);
clReleaseEvent(runEvent);
clReleaseEvent(mapEvent);
getchar();
return ;
}

● 输出结果

Verify passed.

● 注意

■ 事件在声明以后一定要通过某个函数的  cl_event * /* event */  参数定义它,才能进行 clWaitForEvents 或 clReleaseEvent,否则会报错

● 使用 CL_MEM_COPY_HOST_PTR 和 CL_MEM_USE_HOST_PTR 的区别,前者创建一个独立的缓冲区,只是使用了 host_ptr 的值来初始化,后续使用过程中主机端对 host_ptr 的修改不会影响到缓冲区的内容;后者直接使用 host_ptr (转化为设备指针来使用),后续使用过程中主机端对 host_ptr 的修改仍会影响缓冲区内容

● 代码

 #include <cl.h>
#include <stdio.h>
#include <stdlib.h> using namespace std;
const int nElement = ; const char *programSource = " \
__kernel void vectorAdd(__global int *A) \
{ \
return; \
} \
"; int main(int argc, char* argv[])
{
const size_t dataSize = sizeof(int) * nElement;
int i, sum, *A, *returnA, *mapReturnA; A = (int *)malloc(dataSize);
returnA = (int *)malloc(dataSize);
//mapReturnA = (int *)malloc(dataSize);// 注意用作内存映射的指针不需要申请内存,使用这个表达式会造成结尾处的运行时错误
for (i = ; i < nElement; A[i++] = ); cl_int status;
cl_platform_id platform;
clGetPlatformIDs(, &platform, NULL);
cl_device_id device;
clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, , &device, NULL);
cl_context context = clCreateContext(NULL, , &device, NULL, NULL, &status);
cl_command_queue queue = clCreateCommandQueue(context, device, , &status);
cl_program program = clCreateProgramWithSource(context, , &programSource, NULL, &status);
status = clBuildProgram(program, , &device, NULL, NULL, NULL);
cl_kernel kernel = clCreateKernel(program, "vectorAdd", &status); cl_mem clA = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, dataSize, A, NULL);
//cl_mem clA = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, dataSize, A, NULL); for (i = ; i < nElement; A[i++]++);// 在创建缓冲区以后再修改 A 的值 size_t global_work_size = nElement;
clSetKernelArg(kernel, , sizeof(cl_mem), (void*)&clA);
clEnqueueNDRangeKernel(queue, kernel, , NULL, &global_work_size, NULL, , NULL, NULL); clEnqueueReadBuffer(queue, clA, CL_TRUE, , dataSize, returnA, , NULL, NULL);
mapReturnA = (cl_int *)clEnqueueMapBuffer(queue, clA, CL_TRUE, CL_MAP_READ, , dataSize, , NULL, NULL, &status); for (i = sum = ; i < nElement; sum += A[i++]);
printf("sum A = %d\n", sum);
for (i = sum = ; i < nElement; sum += returnA[i++]);
printf("sum returnA = %d\n", sum);
for (i = sum = ; i < nElement; sum += mapReturnA[i++]);
printf("sum mapReturnA = %d\n", sum); free(A);
free(returnA);
clReleaseMemObject(clA);
clReleaseContext(context);
clReleaseCommandQueue(queue);
clReleaseProgram(program);
getchar();
return ;
}

● 输出结果

■ 使用 CL_MEM_COPY_HOST_PTR,仅有主机端的值被修改

sum A =
sum returnA =
sum mapReturnA =

■ 使用 CL_MEM_USE_HOST_PTR,设备端使用的缓冲区也遭到了修改

sum A =
sum returnA =
sum mapReturnA =

OpenCL 三种内存对象的使用的更多相关文章

  1. C++二级指针第三种内存模型

    #include "stdio.h" #include "stdlib.h" #include "string.h" void main() ...

  2. C#中三种定时器对象的比较 【转】

    https://www.cnblogs.com/zxtceq/p/5667281.html C#中三种定时器对象的比较 ·关于C#中timer类 在C#里关于定时器类就有3个1.定义在System.W ...

  3. 深入理解C语言-二级指针三种内存模型

    二级指针相对于一级指针,显得更难,难在于指针和数组的混合,定义不同类型的二级指针,在使用的时候有着很大的区别 第一种内存模型char *arr[] 若有如下定义 char *arr[] = {&quo ...

  4. OpenCL中三种内存创建image的效率对比

    第一种:使用ION: cl_mem_ion_host_ptr ion_host_ptr1; ion_host_ptr1.ext_host_ptr.allocation_type = CL_MEM_IO ...

  5. C#中三种定时器对象的比较

    ·关于C#中timer类 在C#里关于定时器类就有3个1.定义在System.Windows.Forms里2.定义在System.Threading.Timer类里3.定义在System.Timers ...

  6. Servlet学习笔记(1)--第一个servlet&&三种状态对象(cookie,session,application)&&Servlet的生命周期

    servlet的404错误困扰了两天,各种方法都试过了,翻书逛论坛终于把问题解决了,写此博客来纪念自己的第一个servlet经历. 下面我会将自己的编写第一个servlet的详细过程提供给初学者,大神 ...

  7. windows的三种内存管理方法

    Windows的内存管理方法 windows提供了3种方法来进行内存管理: l         虚拟内存,最适合用来管理大型对象或者结构数组 l         内存映射文件,最适合用来管理大型数据流 ...

  8. 转:三种状态对象的使用及区别(Application,Session,Cookie)

    Application状态对象 Application 对象是HttpApplication 类的实例,将在客户端第一期从某个特定的ASP.NET应用程序虚拟目录中请求任何URL 资源时创建.对于We ...

  9. 三种分布式对象主流技术——COM、Java和COBRA

    既上一遍,看到还有一遍将关于 对象的, 分布式对象, 故摘抄入下: 目前国际上,分布式对象技术有三大流派——COBRA.COM/DCOM和Java.CORBA技术是最早出现的,1991年OMG颁布了C ...

随机推荐

  1. 将keras模型在django中应用时出现的小问题——ValueError: Tensor Tensor("dense_2/Softmax:0", shape=(?, 8), dtype=float32) is not an element of this graph.

    本文原出处(感谢作者提供):https://zhuanlan.zhihu.com/p/27101000 将keras模型在django中应用时出现的小问题 王岳王院长 10 个月前 keras 一个做 ...

  2. jq对象和DOM对象的互换

    var oJq;  //JQ对象 var oDom; //dom对象 oDom = oJq[index];  // JQ对象转化为oDom对象 oJq  = $(oDom);      //DOM对象 ...

  3. 移动web开发适配方案之Rem

    移动端为什么要做适配 移动端相对PC端来说大部分浏览器内核都是基于Webkit的,所以大部分都支持CSS3的最新语法.但是由于手机的屏幕尺寸和分辨率都不太一样(尤其是安卓),所以不得不对不同分辨率的手 ...

  4. 這是我既C語言作業寫博客後寫的第一篇博客

    這篇博客應該算是寫給我自己的博客吧,所以這裏我想用繁體字寫,因為我漸漸地發現我已經很少使用到繁體字了,日常QQ聊天都使用簡體字,繁體字都懶得切換了,但是為了不讓別人麻煩,在外界交流的時候我會使用簡體字 ...

  5. JAVA使用ItextPDF

    1.背景 在某些业务场景中,需要提供相关的电子凭证,比如网银/支付宝中转账的电子回单,签约的电子合同等.方便用户查看,下载,打印.目前常用的解决方案是,把相关数据信息,生成对应的pdf文件返回给用户. ...

  6. Win2D 中的游戏循环:CanvasAnimatedControl

    Win2D 是 DirectX 的一个高层封装,提供了极大 DirectX 性能的同时,又具有很好用的 API 设计. 用 Win2D 除了能做出高性能的视觉效果之外,还可以轻而易举地搭建一个游戏循环 ...

  7. flask第二十四篇——模板【6】自定义过滤器

    请关注孟船长的公众号:自动化测试实战 大家想了解其他过滤器可以参考这里: http://jinja.pocoo.org/docs/dev/templates/#builtin-filters ---- ...

  8. 重新理理C++:从《c++ primer》开始

    以前学过C++,但是感觉很多东西还是不清不楚,很多问题解决起来啃吧啃吧的.... 即使c++的东西看过,但是这本书看起来速度还是提不上去,确实需要扎实扎实.很多以前只会用的东西,这本书上都讲的很清楚, ...

  9. MyBatis_Study_002(进阶,增删改查)

    源码:https://github.com/carryLess/mbtsstd-002.git 1.主配置文件 <?xml version="1.0" encoding=&q ...

  10. nginx brotli 压缩试用

    brotli 的压缩比相对gzip 有好多提升 测试试用docker 测试代码 https://github.com/rongfengliang/rollup-babel-demolibrary 运行 ...