为了方便讲述设备队列中的内容,现在我们就对块语法做简要的说明。从OpenCL 2.0开始支持clang Block语法。Block是对C语言的扩展,用来实现闭包的特性。类似于其他语言脚本或者编程语言中的闭包或者是Lambda表示式,可能第一眼看上去有点诡异。我们先来看一个例子如下图所示。
对于如上代码,按照函数调用方式调用块对象变量即可:
int result = myBlock(4) ; //result=28
在例子中,声明myBlock为一个变量,用“^”符号来表示这是一个block。block的输入和返回值为整型数据。block文字开始也用“^”标示,block的实体包含在{}中,并在最后使用“;”来表示结束。通过block文字表达来生成blocks参考。例如:
^ void (void){printf ("hello world\n")};
上述block文字表达生成了一个没有参数也没有返回值的block引用。
上述block文字表达生成了一个没有参数也没有返回值的block引用。
通过上述例子以及图4-10,我们看到对一个block变量的声明非常简单,其语法形式与函数指针几乎一模一样,就是将*变成^。所以用形式化的方法来写就是——〈block返回类型〉(^〈block变量标识符〉)(〈block形参列表〉)。而定义一个block实体的形式化方法为——^(〈block返回类型〉)(〈block实参列表〉){〈block实现的语句块〉}。
而当返回类型为空时,block实体可写为:^(〈实参列表〉){〈block语句块〉}。如果连实际参数列表也为空,则可更简单地写为:^{〈block语句块〉}。
block变量存储的是blocks实体的引用,下面是一些合法的块声明:
//返回void类型,参数也是void类型的块
void (^blockReturningVoidWithVoidArgument)( void );
//返回int类型,两个输入参数分别是int和char类型的块
int (^blockReturningIntWithIntAndCharArguments)( int , char );
下面的例子中,展示了如何在内核函数中使用block调用其他内核函数:
kernel DeviceEnqueueKernelA(global int *input, global int *out)
{
……
}
kernel void CallDeviceEnqueue(global int *input, global int *out)
{
ndrange_t ndrange;
……
void (^device_enqueue)(void) =
^ { DeviceEnqueueKernelA (input, out);};
enqueue_kernel(get_default_queue(), ndrange, device_enqueue);
……
}
关于blocks的更多用法,有兴趣的可以参考OpenCL 2.0 C语言官方编程手册。