▶ 事件的两种使用方法。第一种是用事件 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. Java Spring-事务管理概述

    2017-11-11 23:05:39 事务(Transaction):是逻辑上一组操作,要么全都成功,要么全都失败. 一.事务的特性 原子性:事务不可分割 一致性:事务执行的前后,数据完整性保持一致 ...

  2. JAVA synchronized关键字锁机制(中)

    synchronized 锁机制简单的用法,高效的执行效率使成为解决线程安全的首选. 下面总结其特性以及使用技巧,加深对其理解. 特性: 1. Java语言的关键字,当它用来修饰一个方法或者一个代码块 ...

  3. java裁剪图片

    java裁剪图片保存到指定位置 /** * 图片裁剪通用接口 * * @param src 源图片地址,图片格式PNG * @param dest 目的图片地址 * @param x 图片起始点x坐标 ...

  4. opencv错误(Unhandled expection at at 0x0007EEE...)

    错误截图如下: 情况1:加载人脸检测分类器的时候出错,不能写相对路径一定要写绝对路径 例如:cascade.load("D:\\recognise-your-own-face2\\recog ...

  5. 解析xml(当节点中有多个子节点)

    概要:解析一个xml,当一个节点中又包含多个子节点如何解析,对比一个节点中不包括其他节点的情况. 一,xml样例 <cisReports batNo="查询批次号" unit ...

  6. MAC环境下 Android P 系统源码下载、编译、导入到AS、Pixel2xl刷机 实战

    一.下载源码 1 . 确保主目录下有一个 bin/ 目录,并且该目录包含在路径中: mkdir ~/bin PATH=~/bin:$PATH 2 . 下载 Repo 工具,并确保它可执行: curl ...

  7. 仿智能社官网:原生JS实现简单又酷炫的3D立方体时钟

    先放一下我做的效果:https://linrunzheng.github.io/3Dclock/3Dclock/new.html 至于3D立方体怎么做这里就不在阐述了,可以看一下我之前的博客. 这里默 ...

  8. ubuntu 11.04 old sources.list

    #deb cdrom:[Ubuntu 11.04 _Natty Narwhal_ - Release amd64 (20110427.1)]/ natty main restricted # See ...

  9. Linux升级nodejs及多版本管理

    最近要用到开发要用到nodejs,于是跑到开发机运行了下node,已经安装了,深感欣慰,是啥版本呢?再次运行了下node -v,原来是0.6.x的.估计是早先什么时候谁弄的.那么来升级下node吧. ...

  10. [QT][SQLITE]学习记录一 querry 查询

    使用 QSqlQuery query ; query("SELECT id FROM TABLE1 WHERE id = '2017'); 的到的结果集就是query本身,此时需要使用 qu ...