我正在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++相关问答推荐

如何确保内存分配在地址附近?

为什么海湾合作委员会在共享对象中的. init_data的虚拟内存地址之前留出一个空白

C中空终止符后面的数字?

为什么下面的递归基本情况在C中不起作用?

当main函数调用被重构时,C函数给出错误的结果

C语言中字符数组声明中的标准

为什么在4.9.37版的内核中,kfio还需要smp_wmb呢?

如何在C宏中确定 struct 中元素的类型?

_泛型控制表达式涉及数组碰撞警告的L值转换错误?

GDB输出ARM助记符

Kdb:仅升级指定的列

如何在C中只对字符串(包含数字、单词等)中的数字进行重复操作?

致命错误:ASM/rwan ce.h:没有这样的文件或目录.符号链接还不够

指向不同类型的指针是否与公共初始序列规则匹配?

对于STM32微控制器,全局偏移表.get和.Got.plt必须为零初始化

基于蝶数恰好有8个除数的事实的代码

%g浮点表示的最大字符串长度是多少?

C Makefile - 如何避免重复提及文件名

仅使用其内存地址取消引用 C 中的 struct

int 与 size_t 与 long