第12章 WebCL:使用OpenCL加速Web应用 - 12.3 同步机制

优质
小牛编辑
123浏览
2023-12-01

与C/C++的OpenCL程序一样,设备可以以同步的方式对命令队列中的命令进行处理。主机端将命令提交到命令队列中,然后可以使用clFinish()等待命令队列上所有命令执行完成。

与之相似,在WebCL中webCLCommandQueue类具有两个参数:

  1. event_list——一个WebCLEevet数组
  2. event——用来对设备执行命令的状态进行查询的事件对象

通常,这两参数传的都是null。不过,当有事件传递给某个命令时,主机端可以使用clWaitForEvents用来等待某个命令执行结束。编程者也可以使用事件的回调函数,在对应命令完成时进行提示。这要求主机端代码在事件中提前注册一个回调函数。当event_list传递如命令时,之后命令不会立即执行,只有等到event_list上所有事件对象对应的命令执行完成,才会执行当前的命令。

  1. // Enqueue kernel
  2. try{
  3. kernel_event = new cl.WebCLEvent();
  4. queue.enqueueNDRange(kernel, 2, null, globals, locals, null, null, kernel_event);
  5. } catch(ex) {
  6. throw "Couldn't enqueue the kenrel. " + ex;
  7. }
  8. // Set kernel event handling routines: call kernel_complete()
  9. try{
  10. kernel_event.setCallback(webcl.COMPLETE, kernel_complete, "The kernel finished successfully");
  11. } catch(ex){
  12. throw "Couldn't set callback for event. " + ex;
  13. }
  14. // Read the buffer
  15. var data = new Float32Array(4096);
  16. try{
  17. read_event = new webcl.WebCLEvent();
  18. queue.enqueueReadBuffer(clBuffer, false, 0, 4096 * 4, data, null, read_event);
  19. } catch(ex){
  20. throw "Couldn't read the buffer. " + ex;
  21. }
  22. // register a callback on completion of read_event: calls read_complete()
  23. read_event.setCallback(webcl.COMPLETE, read_complete, "Read complete");
  24. // wait for both events to complete
  25. queue.waitForEvents([kernel_event, read_event]);
  26. // kernel callback
  27. function kernel_complete(event, data){
  28. // event.status = webcl.COMPLETE or error if negative
  29. // event.data is null
  30. // data should contain "The kernel finished successfully"
  31. }
  32. // read buffer callback
  33. function read_complete(event, data){
  34. // event.status = cl.COMPLETE or error if negative
  35. // event.data contains a WebCLMemoryObject with values from device
  36. // data contains "Read complete"
  37. }

以上代码所形成的应用,希望在命令结束时进行提示,那么首先需要创建一个WebCLEvent对象,将命令传递到事件中,然后注册一个JavaScript写的回调函数。注意WebCLEvent.setCallback()的最后一个参数可以是任意对象。还需要注意对WebCLBuffer、WebCLImage的数据读写,clBuffer的所有权从主机端传递到设备端。因此,当read_complete()回调被调动时,clBuffer的所有权已经从设备端转移到主机端。所有权的转移意味着,当主机端没有对应内存的所有权时,是不能访问或使用对应的内存。当会回调函数被调用后,主机端就又能访问内存了。