OpenMP并行实现埃拉托斯特尼筛法出现invalid controlling predicate错误
错误成因
- 编译错误直接原因:OpenMP 规范要求
#pragma omp for修饰的 for 循环,终止判断必须是循环变量与循环外不变量直接进行大小比较,不支持循环变量参与运算的表达式作为判断主体。你的代码中外层循环终止条件为p * p <= n,判断主体是p*p而非循环变量p本身,编译器无法识别为合法的并行循环,因此抛出invalid controlling predicate错误。 - 额外逻辑错误:即使解决编译问题,代码也无法得到正确结果:
prime数组定义在并行块内部,属于线程私有变量,每个线程持有独立副本,不同线程的修改无法同步,结果会完全混乱。- 埃氏筛外层循环天然存在数据依赖:小素数的标记操作必须先完成,更大的
p才能正确判断prime[p]是否为真素数,直接并行外层循环会出现读取prime[p]时前置标记未完成的问题,导致判断错误。
修复方案
按如下步骤修改即可正常运行:
- 提前计算外层循环上限
int sqrt_n = sqrt(n);,将循环条件改为p <= sqrt_n,满足 OpenMP 并行循环的格式要求,解决编译报错。 - 将
prime数组移到并行块外部,声明为共享变量,初始化操作放在并行块前执行,避免多线程私有副本问题。 - 调整并行策略,选择并行内层无数据依赖的标记循环(不同位置的写入操作互不干扰),避免外层循环的依赖问题。
- 修复 main 函数中的参数类型错误、笔误。
修复后完整代码
#include <bits/stdc++.h> #include <iostream> #include <stdio.h> #include <stdlib.h> #include <math.h> #include <omp.h> using namespace std; void SieveOfEratosthenes(int n) { bool *prime = new bool[n + 1]; memset(prime, true, sizeof(bool) * (n + 1)); int sqrt_n = sqrt(n); #pragma omp parallel for schedule(dynamic) for (int p = 2; p <= sqrt_n; p++) { if (prime[p] == true) { #pragma omp simd for (int i = p * p; i <= n; i += p) prime[i] = false; } } for (int p = 2; p <= n; p++) if (prime[p]) printf("%d ", p); delete[] prime; } int main() { printf("Enter the size: "); int n ; scanf("%d", &n); int limit = sqrt(n); printf("Following are the prime numbers from 2 to %d \n", limit); SieveOfEratosthenes(limit); printf("\n"); return 0; }
内容的提问来源于stack exchange,提问作者user17079709
相关产品推荐
相关产品推荐

