OpenCL C编程语言含有一些在一个工作组内跨多个工作项的操作。这些操作称为工作组函数。其中包括工作组栅栏(barrier)操作、扫描、缩减、管道等工作组函数,这些在之前的教程中都有所描述。我们将先讨论工作组栅栏,其他工作组函数将在后面继续讨论。
栅栏函数为内核程序提供了一种在单个工作组内同步工作项的机制:非正式来说,工作组的每个工作项在它们被允许继续执行之前必须执行栅栏操作。栅栏操作也将存储器操作安排到一个指定的对一个或多个地址空间的结合,诸如本地存储器或全局存储器,这类似于一个存储器栅栏(fence)。
为了精确地指定栅栏的存储器次序语义,我们需要区分下栅栏的动态调用实例与静态调用实例。对一个栅栏的调用可以出现在一个循环内,比如,每次执行对同一个静态栅栏的调用,将产生该栅栏的一个新的动态实例,该动态实例将独立地同步一个工作组的工作项。
执行一个栅栏(barrier)操作的动态实例的工作项会产生两个操作,两个都是栅栏(fence),分别称为入口栅栏(entry fence)与出口栅栏(exit fence)。这些栅栏遵守除所有本章所指定的针对栅栏(fence)的规则外,还遵守下列规则:
1)入口栅栏是一个释放栅栏(release fence),并且具有与所请求的栅栏(barrier)操作相同的存储器类型标志以及存储区域。
2)出口栅栏是一个获得栅栏(acquire fence),具有与所请求的栅栏(barrier)操作相同的存储器标志与存储区域。
3)对于每个工作项,入口栅栏次序在出口栅栏之前。
4)如果设置了CLK_GLOBAL_MEM_FENCE存储器标志,那么对于每个工作项而言,当前工作项的入口栅栏全局同步于在同一个工作组中的所有其他工作项的出口栅栏。
5)如果设置了CLK_LOCAL_MEM_FENCE存储器标志,那么对于每个工作项而言,当前工作项的入口栅栏本地同步于同一个工作组中的所有其他工作项的出口栅栏。
其他工作组函数,包括work_group_all()以及work_group_broadcast()等都已经在之前的教程中描述过了。使用这些工作组函数指明了在一个工作项执行时的两条语句之间的前置关系次序,以满足数据依赖性。例如,一个工作项对一个工作组函数提供某个值,这在行为上必须看作为该工作项在开始执行那个工作组函数之前就已经生成了那个值。此外,程序员必须确保一个工作组内的所有工作项必须执行同一个工作组函数的调用点,或动态工作组函数实例。