我在使用此代码时遇到问题,我想我必须使用关键条款,但我不知道如何......
#include <stdio.h>
#include <sys/time.h>
#define N4 5000
#define N5 5000
#define PIXMAX 10
#define NUM_THREADS 4
int i, j, k;
int histo[PIXMAX], image[N4][N5];
void calculate_histo(int *array, int matrix[N4][N5]) {
for(i=0; i<PIXMAX; i++) array[i] = 0;
#pragma omp parallel
{
int array_private[PIXMAX];
for(i=0; i<PIXMAX; i++) array_private[i] = 0;
#pragma omp for
for(i=0; i<N4; i++)
for(j=0; j<N5; j++) {
array_private[matrix[i][j]]++;
}
#pragma omp critical
{
for(i=0; i<PIXMAX; i++) {
array[i] += array_private[i];
}
}
}
}
main ()
{
omp_set_num_threads(NUM_THREADS);
for(i=0; i<N4; i++)
for(j=0; j<N5; j++)
{
if(i%3) image[i][j] = (i+j) % PIXMAX;
else image[i][j] = (i+i*j) % PIXMAX;
}
calculate_histo(histo,image);
for (k=0; k<PIXMAX; k++) printf("%9d", histo[k]);
}
每次运行时都会得到不同的结果, 五次执行中的输出:
1.- 3424378 1765911 2356499 1767451 2354765 2123619 2355686 1767270 2355937 1762464
2.- 3359050 1728213 2310171 1727858 2309947 2094584 2309402 1727705 2310021 1726228
3.- 3479377 1782549 2373773 1783920 2372319 2153420 2374614 1785481 2375290 1781468
4.- 3459613 1781119 2362956 1783067 2362662 2154083 2360726 1781994 2362982 1779394
5.- 3434711 1751408 2349619 1750327 2348681 2104916 2348510 1750427 2350599 1747760
问题解决了,一切正常,感谢您的帮助! 我使用的最终代码是:
有关更多信息,请参阅注释,例如不使用全局变量或使用矩阵[i * 5000 + j]而不是矩阵[i] [j]
#include<stdio.h>
#include<sys/time.h>
#include<omp.h>
#define N4 5000
#define N5 5000
#define PIXMAX 10
#define NUM_THREADS 4
int histo[PIXMAX], image[N4][N5];
int i,j,k;
void calculate_histo(int *array, int matrix[N4][N5]) {
for(i=0; i<PIXMAX; i++) array[i] = 0;
#pragma omp parallel private(i,j)
{
int array_private[PIXMAX];
for(i=0; i<PIXMAX; i++)
array_private[i] = 0;
#pragma omp for
for(i=0; i<N4; i++)
for( j=0; j<N5; j++) {
array_private[matrix[i][j]]++;
}
#pragma omp critical
{
for( i=0; i<PIXMAX; i++) {
array[i] += array_private[i];
}
}
}
}
int main () {
omp_set_num_threads(NUM_THREADS);
for( i=0; i<N4; i++)
for( j=0; j<N5; j++) {
if(i%3)
image[i][j] = (i+j) % PIXMAX;
else
image[i][j] = (i+i*j) % PIXMAX;
}
for ( k=0; k<PIXMAX; k++)
printf("%9d", histo[k]);
printf("\n");
calculate_histo(histo,image);
for ( k=0; k<PIXMAX; k++)
printf("%9d", histo[k]);
printf("\n");
return 0;
}
答案 0 :(得分:1)
您可以使用atomic
来执行此操作,但效率不高。更好的方法是为每个线程使用私有数组,并行填充它们,然后在关键部分填充共享数组。请参阅下面的代码。也可以在没有关键部分的情况下执行此操作,但它有点复杂Fill histograms (array reduction) in parallel with OpenMP without using a critical section
这是我推荐的功能(我使用矩阵[i * 5000 + j]而不是矩阵[i] [j],因为Fortran和C做了彼此相反的索引,我永远不记得哪个是哪个)。
void foo_omp_v2(int *array, int *matrix) {
for(int i=0; i<10; i++) array[i] = 0;
#pragma omp parallel
{
int array_private[10];
for(int i=0; i<10; i++) array_private[i] = 0;
#pragma omp for
for(int i=0; i<5000; i++) {
for(int j=0; j<5000; j++) {
array_private[matrix[i*5000 + j]]++;
}
}
#pragma omp critical
{
for(int i=0; i<10; i++) {
array[i] += array_private[i];
}
}
}
}
这是我使用的完整代码,显示原子更糟糕
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
void foo(int *array, int *matrix) {
for(int i=0; i<10; i++) array[i] = 0;
for(int i=0; i<5000; i++) {
for(int j=0; j<5000; j++) {
array[matrix[i*5000 + j]]++;
}
}
for(int i=0; i<10; i++) {
printf("%d ", array[i]);
} printf("\n");
}
void foo_omp_v1(int *array, int *matrix) {
for(int i=0; i<10; i++) array[i] = 0;
#pragma omp parallel for
for(int i=0; i<5000; i++) {
for(int j=0; j<5000; j++) {
#pragma omp atomic
array[matrix[i*5000 + j]]++;
}
}
for(int i=0; i<10; i++) {
printf("%d ", array[i]);
} printf("\n");
}
void foo_omp_v2(int *array, int *matrix) {
for(int i=0; i<10; i++) array[i] = 0;
#pragma omp parallel
{
int array_private[10];
for(int i=0; i<10; i++) array_private[i] = 0;
#pragma omp for
for(int i=0; i<5000; i++) {
for(int j=0; j<5000; j++) {
array_private[matrix[i*5000 + j]]++;
}
}
#pragma omp critical
{
for(int i=0; i<10; i++) {
array[i] += array_private[i];
}
}
}
for(int i=0; i<10; i++) {
printf("%d ", array[i]);
} printf("\n");
}
int main() {
int array[10];
int *matrix = new int[5000*5000];
for(int i=0; i<(5000*5000); i++) {
matrix[i]=rand()%10;
}
double dtime;
dtime = omp_get_wtime();
foo(array, matrix);
dtime = omp_get_wtime() - dtime;
printf("time %f\n", dtime);
dtime = omp_get_wtime();
foo_omp_v1(array, matrix);
dtime = omp_get_wtime() - dtime;
printf("time %f\n", dtime);
dtime = omp_get_wtime();
foo_omp_v2(array, matrix);
dtime = omp_get_wtime() - dtime;
printf("time %f\n", dtime);
}
以下是适用于GCC和Visual Studio
的代码版本#include <stdio.h>
#include <omp.h>
//#include <sys/time.h>
#define N4 5000
#define N5 5000
#define PIXMAX 10
#define NUM_THREADS 4
int histo[PIXMAX], image[N4][N5];
void calculate_histo(int *array, int matrix[N4][N5]) {
int i;
for(i=0; i<PIXMAX; i++) array[i] = 0;
#pragma omp parallel
{
int i,j;
int array_private[PIXMAX];
for(i=0; i<PIXMAX; i++) array_private[i] = 0;
#pragma omp for
for(i=0; i<N4; i++)
for(j=0; j<N5; j++) {
array_private[matrix[i][j]]++;
}
#pragma omp critical
{
for(i=0; i<PIXMAX; i++) {
array[i] += array_private[i];
}
}
}
}
int main () {
omp_set_num_threads(NUM_THREADS);
int i,j;
for(i=0; i<N4; i++)
for(j=0; j<N5; j++)
{
if(i%3) image[i][j] = (i+j) % PIXMAX;
else image[i][j] = (i+i*j) % PIXMAX;
}
calculate_histo(histo,image);
for (i=0; i<PIXMAX; i++)
printf("%9d", histo[i]);
printf("\n");
}
答案 1 :(得分:1)
您的计划有两个主要问题:
i
和j
omp_set_num_threads
以下是您的来源的固定副本,其中突出显示了更正:
#include<stdio.h>
#include<sys/time.h>
#include<omp.h> // Problem # 2
#define N4 5000
#define N5 5000
#define PIXMAX 10
#define NUM_THREADS 4
int histo[PIXMAX], image[N4][N5];
void calculate_histo(int *array, int matrix[N4][N5]) {
for(int i=0; i<PIXMAX; i++) array[i] = 0;
#pragma omp parallel
{
int array_private[PIXMAX];
for(int i=0; i<PIXMAX; i++) // # Problem # 1
array_private[i] = 0;
#pragma omp for
for(int i=0; i<N4; i++)
for(int j=0; j<N5; j++) { // # Problem # 1
array_private[matrix[i][j]]++;
}
#pragma omp critical
{
for(int i=0; i<PIXMAX; i++) {
array[i] += array_private[i];
}
}
}
}
int main () {
omp_set_num_threads(NUM_THREADS);
for(int i=0; i<N4; i++)
for(int j=0; j<N5; j++) {
if(i%3)
image[i][j] = (i+j) % PIXMAX;
else
image[i][j] = (i+i*j) % PIXMAX;
}
for (int k=0; k<PIXMAX; k++)
printf("%9d", histo[k]);
printf("\n");
calculate_histo(histo,image);
for (int k=0; k<PIXMAX; k++)
printf("%9d", histo[k]);
printf("\n");
return 0;
}
对于第一点,我建议使用C99标准,它允许在函数体内声明变量(从而增强它们的使用位置)。
关于隐式声明:如果你没有在C中声明一个函数,那么假设它的原型返回一个int
并取一个未定义的参数。因此,函数omp_set_num_threads
隐式声明为:
int omp_set_num_threads()
而不是:
void omp_set_num_threads(int );
由于未声明某项功能并非严格意义上的错误,因此如果没有明确告知编制者这样做,编制人员通常不会提出问题。因此,如果您使用:
进行编译gcc foo.c -fopenmp -o foo
这将被忽视。为避免这种陷阱,通常建议使用编译器提供的最大警告级别:
gcc foo.c -fopenmp -Wall -Werror -pedantic -o foo