▶ 事件的两种使用方法。第一种是用事件 a 标记进入命令队列的操作 A,于是后续进入命令队列的操作 B 可以被要求等到前面事件 a 完成(即操作 A 完成)以后才能开始调度执行。第二种是使用用户自定义的事件创造和标记完成操作来手动控制时间,阻塞任务的进行。

● 事件的使用代码(用两向量之和的代码改过来的)

 #include <stdio.h>
#include <stdlib.h>
#include <cl.h> 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()
{
const size_t datasize = sizeof(int) * nElement;
int i, *A, *B, *C;
cl_int status;
cl_event eventList[];// 一个事件列表 A = (int*)malloc(datasize);
B = (int*)malloc(datasize);
C = (int*)malloc(datasize);
for (i = ; i < nElement; A[i] = B[i] = i, i++); cl_uint nPlatform;
clGetPlatformIDs(, NULL, &nPlatform);
cl_platform_id *listPlatform = (cl_platform_id*)malloc(nPlatform * sizeof(cl_platform_id));
clGetPlatformIDs(nPlatform, listPlatform, NULL);
cl_uint nDevice = ;
clGetDeviceIDs(listPlatform[], CL_DEVICE_TYPE_ALL, , NULL, &nDevice);
cl_device_id *listDevice = (cl_device_id*)malloc(nDevice * sizeof(cl_device_id));
clGetDeviceIDs(listPlatform[], CL_DEVICE_TYPE_ALL, nDevice, listDevice, NULL);
cl_context context = clCreateContext(NULL, nDevice, listDevice, NULL, NULL, &status);
cl_command_queue cmdQueue = clCreateCommandQueue(context, listDevice[], , &status);
cl_program program = clCreateProgramWithSource(context, , (const char**)&programSource, NULL, &status);
status = clBuildProgram(program, nDevice, listDevice, NULL, NULL, NULL);
cl_kernel kernel = clCreateKernel(program, "vectorAdd", &status); cl_mem bufferA, bufferB, bufferC;
bufferA = clCreateBuffer(context, CL_MEM_READ_ONLY, datasize, NULL, &status);
bufferB = clCreateBuffer(context, CL_MEM_READ_ONLY, datasize, NULL, &status);
bufferC = clCreateBuffer(context, CL_MEM_WRITE_ONLY, datasize, NULL, &status); eventList[] = clCreateUserEvent(context, &status); // 用户自定义事件
clEnqueueWriteBuffer(cmdQueue, bufferA, CL_FALSE, , datasize, A, , &eventList[], &eventList[]); // 将该行语句标记为 eventList[1],要求它等待 eventList[0],事件列表长度为 1
clEnqueueWriteBuffer(cmdQueue, bufferB, CL_FALSE, , datasize, B, , &eventList[], &eventList[]); // 将该行语句标记为 eventList[2],要求它等待 eventList[0],事件列表长度为 1 clSetKernelArg(kernel, , sizeof(cl_mem), &bufferA);
clSetKernelArg(kernel, , sizeof(cl_mem), &bufferB);
clSetKernelArg(kernel, , sizeof(cl_mem), &bufferC);
size_t globalSize[] = { nElement }, localSize[] = { }; clEnqueueNDRangeKernel(cmdQueue, kernel, , NULL, globalSize, localSize, , eventList, NULL); // 核函数的调用需要等待事件列表,事件列表长度为 3 clSetUserEventStatus(eventList[], CL_COMPLETE);// 自定义完成事件 eventList[0],这样一来写入缓冲区和内核才能开始运行 clEnqueueReadBuffer(cmdQueue, bufferC, CL_TRUE, , datasize, C, , NULL, NULL);
for (i = ; i < nElement; i++)
{
if (C[i] != i + i)
break;
}
printf("Output is %s.\n", (i == nElement) ? "correct" : "incorrect"); free(A);
free(B);
free(C);
free(listPlatform);
free(listDevice);
clReleaseContext(context);
clReleaseMemObject(bufferA);
clReleaseMemObject(bufferB);
clReleaseMemObject(bufferC);
clReleaseCommandQueue(cmdQueue);
clReleaseProgram(program);
clReleaseKernel(kernel);
getchar();
return ;
}

● 输出结果

Output is correct.

● 若将第 58 行注释掉,则程序被挂起,不能结束。

▶ 回调函数,当到达特定状态(用事件定义)时在主机端执行的程序(函数)。一般用于主机端在等待设备端执行的过程中,用于调度其他任务或执行某些辅助计算,提高设备利用效率。

● 回调函数代码(用上面的事件代码改进得到的)

 #include <stdio.h>
#include <stdlib.h>
#include <cl.h> 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; \
} \
"; void hostFunction(int data) // 需要在主机端执行的回调函数
{
printf("<hostFunction> data = %d\n", data);
} void CL_CALLBACK callbackFunction(cl_event eventIn, cl_int status, void *userData) // 注明回调函数,注意参数的固定格式
{
hostFunction(*(int*)userData);
} int main()
{
const size_t datasize = sizeof(int) * nElement;
int i, *A, *B, *C;
cl_int status;
cl_event eventList[];// 一个事件列表 A = (int*)malloc(datasize);
B = (int*)malloc(datasize);
C = (int*)malloc(datasize);
for (i = ; i < nElement; A[i] = B[i] = i, i++); cl_uint nPlatform;
clGetPlatformIDs(, NULL, &nPlatform);
cl_platform_id *listPlatform = (cl_platform_id*)malloc(nPlatform * sizeof(cl_platform_id));
clGetPlatformIDs(nPlatform, listPlatform, NULL);
cl_uint nDevice = ;
clGetDeviceIDs(listPlatform[], CL_DEVICE_TYPE_ALL, , NULL, &nDevice);
cl_device_id *listDevice = (cl_device_id*)malloc(nDevice * sizeof(cl_device_id));
clGetDeviceIDs(listPlatform[], CL_DEVICE_TYPE_ALL, nDevice, listDevice, NULL);
cl_context context = clCreateContext(NULL, nDevice, listDevice, NULL, NULL, &status);
cl_command_queue cmdQueue = clCreateCommandQueue(context, listDevice[], , &status);
cl_program program = clCreateProgramWithSource(context, , (const char**)&programSource, NULL, &status);
status = clBuildProgram(program, nDevice, listDevice, NULL, NULL, NULL);
cl_kernel kernel = clCreateKernel(program, "vectorAdd", &status); cl_mem bufferA, bufferB, bufferC;
bufferA = clCreateBuffer(context, CL_MEM_READ_ONLY, datasize, NULL, &status);
bufferB = clCreateBuffer(context, CL_MEM_READ_ONLY, datasize, NULL, &status);
bufferC = clCreateBuffer(context, CL_MEM_WRITE_ONLY, datasize, NULL, &status); eventList[] = clCreateUserEvent(context, &status);
clEnqueueWriteBuffer(cmdQueue, bufferA, CL_FALSE, , datasize, A, , &eventList[], &eventList[]);
clEnqueueWriteBuffer(cmdQueue, bufferB, CL_FALSE, , datasize, B, , &eventList[], &eventList[]); clSetKernelArg(kernel, , sizeof(cl_mem), &bufferA);
clSetKernelArg(kernel, , sizeof(cl_mem), &bufferB);
clSetKernelArg(kernel, , sizeof(cl_mem), &bufferC);
size_t globalSize[] = { nElement }, localSize[] = { };
clEnqueueNDRangeKernel(cmdQueue, kernel, , NULL, globalSize, localSize, , eventList, NULL); clSetUserEventStatus(eventList[], CL_COMPLETE); clSetEventCallback(eventList[], CL_COMPLETE, callbackFunction, (void*)&i);// 在自定义事件 eventList[0] 完成后允许回调函数开始执行 clEnqueueReadBuffer(cmdQueue, bufferC, CL_TRUE, , datasize, C, , NULL, NULL);
for (i = ; i < nElement; i++)
{
if (C[i] != i + i)
break;
}
printf("Output is %s.\n", (i == nElement) ? "correct" : "incorrect"); free(A);
free(B);
free(C);
free(listPlatform);
free(listDevice);
clReleaseContext(context);
clReleaseMemObject(bufferA);
clReleaseMemObject(bufferB);
clReleaseMemObject(bufferC);
clReleaseCommandQueue(cmdQueue);
clReleaseProgram(program);
clReleaseKernel(kernel);
getchar();
return ;
}

● 输出结果

<hostFunction> data =
Output is correct.

● 用到的定义,cl.h 中

 // 有关 windows 下接口函数和回调函数的标记
#if defined(_WIN32)
#define CL_API_ENTRY
#define CL_API_CALL __stdcall
#define CL_CALLBACK __stdcall
#else
#define CL_API_ENTRY
#define CL_API_CALL
#define CL_CALLBACK
#endif // 有关事件的定义
typedef struct _cl_event* cl_event; // 有关回调函数开始执行的条件的选项
#define CL_COMPLETE 0x0
#define CL_RUNNING 0x1
#define CL_SUBMITTED 0x2
#define CL_QUEUED 0x3 extern CL_API_ENTRY cl_event CL_API_CALL clCreateUserEvent( // 创建用户自定义的事件
cl_context, // 给定上下文
cl_int * // 返回错误代码
) CL_API_SUFFIX__VERSION_1_1; extern CL_API_ENTRY cl_int CL_API_CALL clSetUserEventStatus(// 改变用户自定义事件状态
cl_event, // 给定事件
cl_int // 返回错误代码
) CL_API_SUFFIX__VERSION_1_1; extern CL_API_ENTRY cl_int CL_API_CALL clSetEventCallback( // 调用回调函数
cl_event, // 给定回调函数相关的状态(用事件定义)
cl_int, // 给定开始执行回调函数的条件(即给定事件达到某个状态)
void (CL_CALLBACK *)(cl_event, cl_int, void *), // 回调函数指针(注意参数格式)
void * // 传给回调函数的参数(上述函数指针的第三个参数)
) CL_API_SUFFIX__VERSION_1_1;

OpenCL 事件的使用,以及回调函数的更多相关文章

  1. react native 之 事件监听 和 回调函数

    同原生一样,react native 同样也有事件监听和回调函数这玩意. 场景很多,比如:A界面push到B界面,B界面再pop回A界面,可以给A界面传值或者告诉A刷新界面. 事件监听 事件监听类似于 ...

  2. property的使用(事件可能就是回调函数)

    TOnUserInfoShow = procedure(userName:string;userAge:Integer)of object;//定义事件模型中的回调函数原型 TUserInfo = c ...

  3. 小兔JS教程(三)-- 彻底攻略JS回调函数

    这一讲来谈谈回调函数. 其实一句话就能概括这个东西: 回调函数就是把一个函数当做参数,传入另一个函数中.传进去的目的仅仅是为了在某个时刻去执行它. 如果不执行,那么你传一个函数进去干嘛呢? 就比如说对 ...

  4. Java|今天起,别再扯订阅和回调函数

    编程史上有两个令人匪夷所思的说辞,一个是订阅,一个是回调函数. 我想应该还有很多同学为“事件的订阅”和“回调函数”所困扰,因为事情本来就不应该按这个套路来解释. 多直白,所谓的“回调函数”你完全可以线 ...

  5. JavaScript 回调函数中的 return false 问题

    今天一个同事问了我一个问题,就是在 Ajax 方法中,请求成功后(success)的回调函数中根据响应的值来判断程序是否继续执行,他不解的是在回调函数中已经 return false 了,但是 Aja ...

  6. PHP回调函数的几种用法

    PHP回调函数的实现方法 目录 前言      全局函数的回调      类静态函数的回调      对象的方法的回调      PHP事件模型(观察者模式)的实现思路    前言 最近在开发一个PH ...

  7. js中的回调函数 和promise解决异步操作中的回调地狱问题。

    回调函数 : 函数作为参数传递到另外一个函数中.简单数据类型和引入数据类型中的数组和对象作为参数传递大家肯定都不陌生,其实引用数据类型中的函数也是可以的. 事实上大家见到的很多,用到的也很多,比如jQ ...

  8. android 回调函数使用简介

    //1---定义回调函数 public interface GirdMenuStateListener { void onSuccess(); void onError(); } //2---使用的地 ...

  9. JS之Callback function(回调函数)

    JS中的回调函数: 1.概念: 函数a有一个参数,这个参数是个函数b,当函数a执行完以后执行函数b,那么这个过程就叫回调,即把函数作为参数传入到另一个函数中,这个函数就是所谓的回调函数. 2.举例: ...

  10. JavaScript Callback 回调函数

    JavaScript callback回调函数 你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货.在这 ...

随机推荐

  1. sql语句中处理金额,把分换算成元

    问题,sql语句中直接将金额/100返回的结果会有多个小数位. as value from account as acc left join conCategory as cate on acc.ca ...

  2. Vue跨路由触发事件,Vue监听sessionStorage

    近来,在做公司的聊天系统,引用的是极光的api.项目需求实时监听别人发过来的消息,进行渲染到页面,还有历史记录也要渲染,历史记录和实时聊天记录返回的结构体还不一样,看到需求的我欲哭无泪,首先登录是在首 ...

  3. poj 2029 Get Many Persimmon Trees 各种解法都有,其实就是瞎搞不算吧是dp

    连接:http://poj.org/problem?id=2029 题意:给你一个map,然后在上面种树,问你h*w的矩形上最多有几棵树~这题直接搜就可以.不能算是DP 用树状数组也可作. #incl ...

  4. iptable filter nat MASQUERADE snat dat

    在这里,系统会根据IP数据包中的destination ip address中的IP地址对数据包进行分发.如果destination ip adress是本机地址,数据将会被转交给INPUT链.如果不 ...

  5. 【hive】时间段为五分钟的统计

    问题内容 今天遇到了一个需求,需求就是时间段为5分钟的统计.有数据的时间戳.对成交单量进行统计. 想法思路 因为数据有时间戳,可以通过from_unixtime()来获取具体的时间. 有了具体的时间, ...

  6. oracle分区交换技术

    交换分区的操作步骤如下: 1. 创建分区表t1,假设有2个分区,P1,P2.2. 创建基表t11存放P1规则的数据.3. 创建基表t12 存放P2规则的数据.4. 用基表t11和分区表T1的P1分区交 ...

  7. CF 148D Bag of mice 概率dp 难度:0

    D. Bag of mice time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...

  8. MHA-ATLAS-MySQL高可用2

    六,配置VIP漂移 主机名 IP地址(NAT) 漂移VIP 描述 mysql-db01 eth0:192.168.0.51 VIP:192.168.0.60 系统:CentOS6.5(6.x都可以) ...

  9. LINQ 分页 和存储过程分页

    存储过程分页 SELECT * FROM ( SELECT ROW_NUMBER() OVER(ORDER BY CreateDate DESC) AS RowNo, EstateAddress, E ...

  10. Android 4.3发布 新增4大改变25日推送升级[附Android 4.3 工厂镜像]

    北京时间7月25日,谷歌举行发布会,正式发布了全新的Nexus 7平板电脑以及Android 4.3系统. 其中Android 4.3系统隶属于4.X果冻豆(Jelly Bean)系列,是目前最新的操 ...