我正在尝试实现一个操纵矩阵的二维模板算法。对于矩阵中的每个字段,将其上、下、左、右的字段相加并除以 4 以计算新值。对于给定的矩阵,这个过程可能会重复多次。
该程序是用 C 语言编写的,并使用 cilkplus gcc 二进制文件进行编译。
**编辑:我认为您可能对编译器标志感兴趣:
~/cilkplus/bin/gcc -fcilkplus -lcilkrts -pedantic-errors -g -Wall -std=gnu11 -O3 `pkg-config --cflags glib-2.0 gsl` -c -o sal_cilk_tst.o sal_cilk_tst.c
请注意,实际代码涉及一些指针算法以保持一切一致。顺序实现有效。我在这里省略了这些步骤以增强可理解性。
伪代码看起来像这样(没有边缘情况处理):
for(int i = 0; i < iterations; i++){
for(int j = 0; j < matrix.width; j++){
for(int k = 0; k < matrix.height; k++){
result_ matrix[j][k] = (matrix[j-1][k] +
matrix[j+1][k] +
matrix[j] [k+1] +
matrix[j] [k-1]) / 4;
}
}
matrix = result_matrix;
}
然后将模板计算本身移至函数apply_stencil(...)
for(int i = 0; i < iterations; i++){
for(int j = 0; j < matrix.width; j++){
for(int k = 0; k < matrix.height; k++){
apply_stencil(matrix, result_matrix, j, k);
}
}
matrix = result_matrix;
}
并尝试并行化:
for(int i = 0; i < iterations; i++){
for(int j = 0; j < matrix.width; j++){
cilk_for(int k = 0; k < matrix.height; k++){ /* <--- */
apply_stencil(matrix, result_matrix, j, k);
}
}
matrix = result_matrix;
}
Floating point exception
此版本编译时没有错误/警告,但在执行时会直接产生一个。如果您想知道:将哪个 for 循环制成 cilk_for 循环并不重要。所有配置(除了没有 cilk_for)都会产生相同的错误。
可能的其他方法:
for(int i = 0; i < iterations; i++){
for(int j = 0; j < matrix.width; j++){
for(int k = 0; k < matrix.height; k++){
cilk_spawn apply_stencil(matrix, result_matrix, j, k); /* <--- */
}
}
cilk_sync; /* <--- */
matrix = result_matrix;
}
这会在编译时产生 3 个警告:i, j
并且k
似乎未初始化。尝试执行时,执行该matrix = result_matrix;
步骤的函数似乎未定义。
现在是实际问题:Cilk 为什么以及如何破坏我的顺序代码;或者更确切地说,我怎样才能阻止它这样做?
如果您有兴趣,实际代码当然也可用。然而,这个项目是针对大学课程的,因此会受到其他学生的抄袭,这些学生发现了这个线程,这就是为什么我不想公开分享它。
**更新:
正如建议的那样,我尝试仅使用 1 个工作线程运行该算法,从而有效地使 cilk 实现顺序化。令人惊讶的是,这确实很好。但是,一旦我将工人的数量更改为两个,熟悉的错误就会返回。
我不认为这种行为是由竞争条件引起的。由于工作矩阵在每次迭代后都会更改cilk_sync
并被调用,因此实际上没有临界区。所有线程不依赖于其他人在同一迭代中写入的数据。
我将尝试的下一步是尝试其他版本的 cilkplus 编译器,看看它是否可能是他们一方的错误。