我正在实现thrust::max_element
搜索算法使用的自定义二进制谓词。它还跟踪算法本身无法产生的感兴趣的值。它看起来像这样:
struct cmp_class{
cmp_class(int *val1){
this->val1 = val1;
}
bool operator()(int i, int j){
if (j < *val1) { *val1 = j; }
return i < j;
}
int *val1;
};
int val1 = ARRAY[0];
std::max_element(ARRAY, ARRAY+length, cmp(&val1));
.... use val1
我的实际二元谓词相当复杂,但上面的例子捕获了它的要点:我将指向整数的指针传递给二进制谓词cmp
,然后写入该整数以保持追踪某些价值(这里是最低限度)。由于max_element
首先调用cmp()(ARRAY[0],ARRAY[1])
然后调用cmp()(running maximum,ARRAY[i])
,我只会查看j
内的值cmp
,因此会初始化val1 = ARRAY[0]
以确保{{1}考虑到了。
如果我在主机上执行上述操作,例如使用ARRAY[0]
,则可以正常工作。鉴于已知数据,std::max_element
的值是我所期望的。但是,使用Thrust在GPU上执行此操作,其值已关闭。我怀疑这是由于val1
的并行化,它是在子数组上递归应用的,其结果形成另一个运行thrust::max_element
的数组,等等。这有用吗?
答案 0 :(得分:2)
通常,用于推力减少的二元谓词预计是可交换的。我在这里使用“可交换”意味着谓词结果应该是有效的,无论参数的显示顺序如何。
在推力平行减少的初始阶段,参数很可能以您可能预期的顺序呈现(即按照传递给reduce函数的向量的顺序,或者按照值出现在单个向量。)然而,在并行缩减过程的后期,在并行扫描期间,参数的起源可能会混淆。假定对参数进行排序的任何二元比较函子都可能被破坏,以推进并行减少。
在您的情况下,无论所呈现的参数顺序如何,比较仿函数的布尔结果都应该是有效的,并且在这方面它似乎是正确的可交换的。
但是,关于val1内置的自定义存储功能,val1
中的结果可能会有所不同,具体取决于参数传递给仿函数的顺序。在传递给函子的设定值中考虑这个简单的最大查找序列为(i,j)(假设val1以较大的值开始):
values: 10 5 3 7 12
comparison pairs: (10,5) (10,3) (10,7) (10,12)
comparison result: 10 10 10 12
val1 storage: 5 3 3 3
现在假设我们只是颠倒了参数呈现给仿函数的顺序:
values: 10 5 3 7 12
comparison pairs: (5,10) (3,10) (7,10) (12,10)
comparison result: 10 10 10 12
val1 storage: 10 10 10 10
另一个问题是,我可以看到val1
上没有原子保护:
if (j < *val1) { *val1 = j; }
上述代码行在串行实现中可能没问题。在并行多线程算法中,您可以同时访问多个线程(同时读取和写入)*val1
,这将导致未定义的结果。