我正在尝试为一些C练习构建一个主要的查找器。我已经算法了,我做了一堆优化以使其更快,然后我决定尝试并行化它,因为,嘿,为什么不呢!原来比我想象的更难。我可以让所有线程运行相同的进程(使用相同的args),或者如果我尝试为每个进程提供不同的args,则会运行单个线程。我真的不知道我在这里做了什么,但你可以看到我在这段代码中使用的一些实验值:
// gcc -std=c99 -o multithread multithread.c -fopenmp -lm
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
int pf(unsigned int start, unsigned int limit, unsigned int q);
int main(int argc, char *argv[])
{
printf("prime finder\n");
int j, slimits[4] = {1,10000000,20000000,30000000}, elimits[4] = {10000000,20000000,30000000,40000000};
double startTime = omp_get_wtime();
#pragma omp parallel shared(slimits, elimits primes)
{
#pragma omp for
for (j = 0; j < 4; j++)
{
primes += pf(slimits[j], elimits[j], atoi(argv[2]));
}
}
printf("%d prime numbers found in %.2f seconds.\n\n", primes, omp_get_wtime() - startTime);
return 0;
}
我没有包含pf函数,因为它非常大但它可以独立工作,它返回找到的素数。我确定问题出在某处。 任何帮助将不胜感激!
答案 0 :(得分:2)
你至少犯了一个显而易见的(对我来说)和严重的错误。您已声明primes
已共享并允许程序中的所有线程更新它。因此,您编写了一个数据竞赛程序。 OpenMP中没有任何内容(如果我没记错的话,在C中也没有)保证+=
将以原子方式实现。你还没有真正指出你的程序有什么问题,或者问题是什么,但这肯定是其中之一。
我会告诉你如何解决这个问题,但我认为你应该先解决一个更严重的底层设计问题。您似乎已经决定运行4个线程,并且应该将整数范围除以测试primality为4并将一个块传递给每个线程。当然,你可以做到这一点,但这不是一个使用OpenMP的聪明方法。这也不是划分素性测试工作的明智方法。
OpenMP程序设计的一种更智能的方法是首先不对可执行程序可用的线程数做出假设。设计任意数量的线程,不要设计一个程序,其行为取决于它在运行时获得的线程数。使用OpenMP的工具,特别是schedule
子句,在运行时分配工作负载。
转向素性测试。绘制或至少考虑点(i,t(i))
的散点图,其中i
是整数,t(i)
是确定i
是否为N
所需的时间主要。该图中的模式与整数中素数出现的图中的模式一样难以辨别。换句话说,确定整数的素数的时间是非常不可预测的。随着整数的增加,它确实会上升(好吧,排除大的偶数整数,我确信你的测试不会考虑)。
这种不可预测性的一个含义是,如果将整数范围划分为N
个子范围,并为每个1..m
个线程提供一个子范围,则不会给予线程相同的数量要做的工作。实际上,在整数范围m
(任何is_prime
)中,有一个整数需要比该范围内的任何其他整数测试更长的时间,并且这个时间是您的程序将采用的不可减少的最小值。 。范围的天真分布将产生严重不平衡的工作量。
以下是我认为您应该采取的措施来修复您的计划。
首先,编写一个测试单个整数的素数的函数。这将是您计算的基本任务。请拨打此schedule
。接下来,研究并行for
构造的reduction
子句。 OpenMP提供了许多任务调度选项,我不会在这里解释,你会在网上找到很多好的文档。最后,还要研究#pragma omp parallel shared(slimits, elimits primes)
{
#pragma omp for
for (j = 0; j < 4; j++)
{
primes += pf(slimits[j], elimits[j], atoi(argv[2]));
}
}
条款;这为您编程的数据竞争提供了解决方案。
应用所有这些我建议你改变
#pragma omp parallel shared(slimits, elimits, max_int_to_test)
{
#pragma omp for reduction(+:primes) schedule (dynamic, 10)
for (j = 3; j < max_int_to_test; j += 2)
{
primes += is_prime(j);
}
}
到
{{1}}
运气好的话,我的基本C语言并没有过多地搞砸了语法。