我正在使用openMP编写Longest Common Subsequence算法的并行版本。
顺序版本如下(并且它可以正常工作):
// Preparing first row and first column with zeros
for(j=0; j < (len2+1); j++)
score[0][j] = 0;
for(i=0; i < (len1+1); i++)
score[i][0] = 0;
// Calculating scores
for(i=1; i < (len1+1); i++) {
for(j=1; j < (len2+1) ;j++) {
if (seq1[i-1] == seq2[j-1]) {
score[i][j] = score[i-1][j-1] + 1;
}
else {
score[i][j] = max(score[i-1][j], score[i][j-1]);
}
}
}
关键部分是填写得分矩阵,这是我尝试主要并行化的部分。
一种方法(我选择)是:通过反对角线填充矩阵,因此始终满足左,上和左上依赖。简而言之,我跟踪对角线(第三个循环,下面的变量 i )并且线程平行填充该对角线。 为此,我写了这段代码:
void parallelCalculateLCS(int len1, int len2, char *seq1, char *seq2) {
int score[len1 + 1][len2 + 1];
int i, j, k, iam;
char *lcs = NULL;
for(i=0;i<len1+1;i++)
for(j=0;j<len2+1;j++)
score[i][j] = -1;
#pragma omp parallel default(shared) private(iam)
{
iam = omp_get_thread_num();
// Preparing first row and first column with zeros
#pragma omp for
for(j=0; j < (len2+1); j++)
score[0][j] = iam;
#pragma omp for
for(i=0; i < (len1+1); i++)
score[i][0] = iam;
// Calculating scores
for(i=1; i < (len1+1); i++) {
k=i;
#pragma omp for
for(j=1; j <= i; j++) {
if (seq1[k-1] == seq2[j-1]) {
// score[k][j] = score[k-1][j-1] + 1;
score[k][j] = iam;
}
else {
// score[k][j] = max(score[k-1][j], score[k][j-1]);
score[k][j] = iam;
}
#pragma omp atomic
k--;
}
}
}
}
前两个循环(第一行和第一列)正常工作,并且线程以平衡的方式填充单元格。
当填充矩阵(对角线)时,没有什么效果好。我试图调试它,但似乎线程随机地动作和写东西。
我无法弄清楚出了什么问题,因为在前两个循环中根本没有问题。
有什么想法吗?
P.S。我知道以对角方式访问矩阵对缓存不友好,线程可能不平衡,但我现在只需要它就可以工作了。
P.S。 #2我不知道它是否有用,但我的CPU最多有8个线程。
答案 0 :(得分:0)
以下嵌套for
循环
#pragma omp for
for(j=1; j <= i; j++)
将并行执行,每个线程的j
值不同,没有特定的顺序。
由于omp for
部分中未指定任何内容,因此默认情况下将在所有线程之间共享k
。因此,根据线程的顺序,k
将在未知时间递减(即使使用omp atomic
)。因此,对于固定的j
,k
的值可能会在执行for循环体(在if
子句之间,...)之间发生变化。
答案 1 :(得分:0)
#pragma omp atomic
表示处理器将一次执行一个操作。您正在寻找#pragma omp for private(k)
:处理器将不再共享相同的值。再见,弗朗西斯