12.3 同步机制
与C/C++的OpenCL程序一样,设备可以以同步的方式对命令队列中的命令进行处理。主机端将命令提交到命令队列中,然后可以使用clFinish()等待命令队列上所有命令执行完成。
与之相似,在WebCL中webCLCommandQueue类具有两个参数:
- event_list——一个WebCLEevet数组
- event——用来对设备执行命令的状态进行查询的事件对象
通常,这两参数传的都是null。不过,当有事件传递给某个命令时,主机端可以使用clWaitForEvents用来等待某个命令执行结束。编程者也可以使用事件的回调函数,在对应命令完成时进行提示。这要求主机端代码在事件中提前注册一个回调函数。当event_list传递如命令时,之后命令不会立即执行,只有等到event_list上所有事件对象对应的命令执行完成,才会执行当前的命令。
// Enqueue kernel
try{
kernel_event = new cl.WebCLEvent();
queue.enqueueNDRange(kernel, 2, null, globals, locals, null, null, kernel_event);
} catch(ex) {
throw "Couldn't enqueue the kenrel. " + ex;
}
// Set kernel event handling routines: call kernel_complete()
try{
kernel_event.setCallback(webcl.COMPLETE, kernel_complete, "The kernel finished successfully");
} catch(ex){
throw "Couldn't set callback for event. " + ex;
}
// Read the buffer
var data = new Float32Array(4096);
try{
read_event = new webcl.WebCLEvent();
queue.enqueueReadBuffer(clBuffer, false, 0, 4096 * 4, data, null, read_event);
} catch(ex){
throw "Couldn't read the buffer. " + ex;
}
// register a callback on completion of read_event: calls read_complete()
read_event.setCallback(webcl.COMPLETE, read_complete, "Read complete");
// wait for both events to complete
queue.waitForEvents([kernel_event, read_event]);
// kernel callback
function kernel_complete(event, data){
// event.status = webcl.COMPLETE or error if negative
// event.data is null
// data should contain "The kernel finished successfully"
}
// read buffer callback
function read_complete(event, data){
// event.status = cl.COMPLETE or error if negative
// event.data contains a WebCLMemoryObject with values from device
// data contains "Read complete"
}
以上代码所形成的应用,希望在命令结束时进行提示,那么首先需要创建一个WebCLEvent对象,将命令传递到事件中,然后注册一个JavaScript写的回调函数。注意WebCLEvent.setCallback()的最后一个参数可以是任意对象。还需要注意对WebCLBuffer、WebCLImage的数据读写,clBuffer的所有权从主机端传递到设备端。因此,当read_complete()回调被调动时,clBuffer的所有权已经从设备端转移到主机端。所有权的转移意味着,当主机端没有对应内存的所有权时,是不能访问或使用对应的内存。当会回调函数被调用后,主机端就又能访问内存了。