主機端的同步主要是對命令隊列的操作。在將一個 OpenCL 命令提交到命令隊列的時候,有個參數用來標識是以阻塞還是非阻塞的方式執行。
- 阻塞:該函數會等待,直到命令執行完成後才返回。當後續處理需要依賴該函數處理的結果時,可在該函數返回後放心使用它返回的數據;
- 非阻塞:函數無需等到執行的任務完成就返回。該線程接下來可以馬上處理其它的事情,以提高並行效率。如果後續處理依賴該函數返回的數據就要使用阻塞的方式。
除了在將 OpenCL 命令提交到命令隊列時執行同步操作,也可以通過調用下面的命令執行顯式的同步操作:
clFlush 操作
將前面提交到命令隊列中的 OpenCL 命令發送到和這個命令隊列關聯的設備。
cl_int clFlush (cl_command_queue command_queue)
clFlush 只保證所有提交到 command_queue 命令隊列中的命令發送到了對應的設備,並不能保證在 clFlush 返回後這些命令已經執行完成。
值得注意的是,某些以阻塞的方式提交到命令隊列中的 OpenCL 命令執行了一個隱式的 flush 動作。這樣的函數返回後,命令隊列中的所有命令已經發送到了相應的設備。
clFinish 操作
cl_int clFinish (cl_command_queue command_queue)
該函數進入阻塞狀態,直到前面提交到 command_queue
命令隊列的 OpenCL 命令發送到對應的設備,並且已經執行完成。clFinish 函數是使用的比較頻繁的同步點。
示例程序
程序 OpenCLSyncHost 在主機端分配了一個內存和兩個緩衝區對象,然後分別以阻塞的方式和非阻塞的方式將主機端內存中的內容寫到緩衝區對象所引用的全局內存區域中。程序執行完成後,以阻塞方式和非阻塞方式來寫緩衝區對象所使用的時間如下:
shell@HWFRD:/data/local/tmp/opencl/sync/host $ ./opencl_sync
Test: write memory object1, 47673.958000 us
Test: write memory object2, 31721.875000 us
Test: write memory object1 non-block, 39.063000 us
Test: write memory object2 non-block, 28.646000 us
Test: finish command queue, 20805.729000 us
可以發現,使用阻塞的方式將主機端內存中的數據寫到緩衝區對象所花的時間分別是 47673 微秒和 31721 微秒;而非阻塞時,所用的時間非別是 39 微秒和 28 微秒。執行 clFinish,等待直到命令隊列中的 OpenCL 命令執行完成,所花的時間爲 20805 微秒。
參考
- OpenCL異構並行計算:原理、機制與優化實踐