我正在try 使用C中的OMP将两个n乘以n的矩阵相乘. 但我的代码只计算对角线元素.以下是代码:

我的代码

# include <stdio.h>
# include <omp.h>

int main(void){

  int N, element, tid;
  int i, j;
  scanf("%d", &N); // matrix dimension
  
  int A[N][N]; // matrix A
  int B[N][N]; // matrix B
  int C[N][N]; // matrix C := AB
  
  // declare elements matrix A
  for(i = 0; i < N; i++){
    for(j = 0; j < N; j++){
      scanf("%d", &element);
      A[i][j] = element;
    }
  }

  // declare elements matrix B
  for(i = 0; i < N; i++){
    for(j = 0; j < N; j++){
      scanf("%d", &element);
      B[i][j] = element;
    }
  }
  
  omp_set_num_threads(N); // set the number of threads

  #pragma omp parallel default(none) shared(A, B, C, N) private(i, j, tid) 
  { 
    tid = omp_get_thread_num(); // returns the number of the currently executing thread within the team
    #pragma omp for 
    for (i = 0; i < N; i++){
      C[tid][i] = 0;
      for (j = 0; j < N; j++){
        //tid = i*n + j;
        C[tid][i] += A[tid][j]*B[j][i];
      }
    }
  }

  // print matrix C 
  for(i = 0; i < N; i++){
    for(j = 0; j < N; j++){
      printf("%d ", C[i][j]);
    }
    printf("\n");
  }

  return(0);
}\

这是我用N=2和矩阵A={{1,2},{3,4}}B={{1,2},{3,4}得到的结果

C={{7,随机数},{随机数,22}}

推荐答案

让我们看看您的代码是如何运行的:

#pragma omp parallel default(none) shared(A, B, C, N) private(i, j, tid) 

创建N个线程,这些线程都将执行下一条指令.

#pragma omp for 
    for (i = 0; i < N; i++){

将N次迭代分布到N个线程.使用默认的OMP调度,第一线程(tid=0)将只执行第一次迭代(i=0),第二线程(tid=1)只执行第二次迭代(i=1),依此类推……这意味着在循环体中,您总是得到i = tid,因此C[tid][i]只处理对角线元素.

您应该通过按下#pragma omp for来获得所需的结果,这样i上的循环就可以由每个线程完全执行.但正如在 comments 中提到的,这种创建N线程的方法将在N大于核心数量时提供较差的性能(并且当N小于核心数量时不会使用所有核心).

EDIT

正确的方法是不更改默认线程数(通常等于物理核心数),并定义将行分配给线程的并行循环:

  #pragma omp parallel default(none) shared(A, B, C, N) 
  { 
    #pragma omp for
    for (int k = 0; k < N; i++) {
      for (int i = 0; i < N; i++){
        C[k][i] = 0;
        for (int j = 0; j < N; j++){
          C[k][i] += A[k][j]*B[j][i];
        }
      }
    }
  }

例如,如果N=15,并且有4个线程:

  • 第一个线程将处理k=0,1,2,3的迭代
  • 第二个线程将处理k=4,5,6,7的迭代
  • 第三个线程将处理k=8,9,10,11的迭代
  • 第四个线程将处理k=12、13、14的迭代

但请注意,即使在没有OpenMP的情况下串行执行,此代码也可能效率不高.内部循环中B上的内存访问模式很差,因为它寻址内存中的非连续元素.对于较小的N,这并不重要,但对于较大的N,这可能会导致大量的缓存未命中,然后改变性能.

C++相关问答推荐

为什么下面的C代码会进入无限循环?

ATmega328P USART发送字符重复打印

为什么我得到更多的256假阳性在PKZIP解密密钥验证?

如何解决C中的严格别名?

C中是否有语法可以直接初始化一个常量文本常量数组的 struct 成员?

在列表中插入Int指针(C)

进程已完成,退出代码为138 Clion

如何使用C++在控制台中以彩色打印被阻止的客户端

Zlib:解压缩大文件导致";无效代码长度设置";错误

为什么Linux无法映射这个PT_LOAD ELF段?

C++中PUTS函数的返回值

Realloc():中止的下一个大小无效(核心转储)

为什么会导致分段故障?(C语言中的一个程序,统计文件中某个单词的出现次数)

将某些内容添加到链接列表时,列表中的其他项将使用最后添加的项的名称

atoi函数最大长-长误差的再创造

在分配内存后使用指针是未定义的行为吗?

从管道读取数据时丢失

为什么我的条件不起作用?使用 fgets 输出

缺少 memset_s (C11) 的重要原因

从 COBOL 调用外部 C 库