Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何正确使用OpenMP?_C_Linux_Multithreading_Openmp_Matrix Multiplication - Fatal编程技术网

C 如何正确使用OpenMP?

C 如何正确使用OpenMP?,c,linux,multithreading,openmp,matrix-multiplication,C,Linux,Multithreading,Openmp,Matrix Multiplication,我正在建立一个程序,可以将两个矩阵相乘。问题是,我应该使用OpenMP并行化,但每次只使用一个“for”循环(首先是外部循环,然后是其子循环,然后是内部循环),对于每个并行化方法,我应该在使用不同数量的线程(1,2,4,8,16,32,64128)时分析结果 我的问题是,我应该将OpenMP并行/私有部分放在哪里,以及哪些变量应该是私有/共享的以实现这一点 // code to be parallelized using n_threads omp_set_dynamic(0); //

我正在建立一个程序,可以将两个矩阵相乘。问题是,我应该使用OpenMP并行化,但每次只使用一个“for”循环(首先是外部循环,然后是其子循环,然后是内部循环),对于每个并行化方法,我应该在使用不同数量的线程(1,2,4,8,16,32,64128)时分析结果

我的问题是,我应该将OpenMP并行/私有部分放在哪里,以及哪些变量应该是私有/共享的以实现这一点

// code to be parallelized using n_threads
omp_set_dynamic(0);     // Explicitly disable dynamic teams
omp_set_num_threads(n_threads);


#pragma omp parallel for shared(a, b, c) private(i,j)
for (i=0; i < TAM_MATRIZ; i++){
  for (j=0; j < TAM_MATRIZ; j++) {
    c[i][j] = 0; // initialize the result matrix with zeros
    for (k=0; k < TAM_MATRIZ; k++){
      #pragma omp atomic
      c[i][j] +=  a[i][k]*b[k][j];
    }
  }
  printf("Number of threads used: %d\n", omp_get_num_threads()); 
}
//要使用n\u线程并行化的代码
omp_集_动态(0);//显式禁用动态团队
omp_集合_num_线程(n_线程);
#pragma omp并行用于共享(a,b,c)私有(i,j)
对于(i=0;i
编辑

实际上,它有三个程序,第一个程序只并行外部循环,第二个程序只并行中间循环,最后一个程序并行内部循环。 每个版本应该使用指定的线程(1,2,4,8,16,32,64128)运行8次,然后我们应该比较不同程序版本和使用不同线程号的相同版本的性能

我的疑问在于,应该在哪里共享或使私有it变为变量。并行第一个循环时,应该共享哪些变量?当我处理第二个循环时,共享哪些变量?等等


在我看来,我不能共享任何变量,因为我将有多个线程同时工作,并且可以产生部分结果,但我知道我错了,我在这里问的基本上是为了理解为什么。

你的思路是正确的-这其实很简单

  • 您在
    private
    子句中遗漏了
    k
    ——这将导致问题,因为在外部定义时,默认情况下是
    shared
    。最好的方法不是为每个变量显式地选择数据共享,而是尽可能在本地声明变量(例如,
    for(int…)
    ,这几乎总是需要的,而且更容易推理。
    a
    b
    c
    ,来自外部,隐式
    共享
    -循环变量在内部声明,隐式
    私有

  • <> L>>P>幸运的是,不需要<代码>α-PrimaOMP原子< /代码>。每个线程在不同的<代码> i>代码> -所以没有两个线程可以尝试更新相同的<代码> [i] [j] < /代码>。删除<代码>原子< /代码>将极大地提高性能。如果你需要原子,也可以考虑减少作为替代。

  • 如果你想打印
    omp\u get\u num\u threads
    ,你应该在循环外,但在并行区域内打印。在你的情况下,这意味着你必须将
    omp parallel for
    拆分为
    omp parallel
    omp for
    。使用
    omp single
    确保只有一个线程输出

请注意,矩阵乘法的良好性能要复杂得多,超出了本问题的范围

编辑:

对于嵌套循环,如果可能,通常最好将最外层的循环并行化-即没有数据依赖性阻止它。有时最外层的循环不能产生足够的并行性-在这种情况下,您宁愿使用
collapse(2)
来并行化外层的2个循环。不要使用
(并行)对于
两次,除非您完全知道自己在做什么。原因是并行化中间循环会产生更多较小的工作,从而增加相对开销

在您的特定情况下,可以安全地假设
TAM_MATRIZ>>n_线程
0,这意味着最外层的循环具有足够的并行功,可以有效地使用所有线程

重申数据共享规则。适用于正常的
并行
区域

  • 并行
    区域的词法范围内定义的变量(和并行循环变量)是隐式私有的。这些是线程处理的变量。如果变量仅在词法范围内使用,则始终1在最窄的词法范围内定义它
  • 默认情况下,词法范围外定义的变量是隐式共享的。这些变量通常是并行区域的输入/输出-因此必须共享。请确保避免数据争用
如果您遵循这一点,几乎不需要显式定义
私有
/
共享
数据共享属性2

0否则在此处使用OpenMP甚至没有意义

例外情况适用于不昂贵C++类型的不平凡C++类型。


<代码> < <代码> >代码>第一私密< /代码>有助于显式使用。

< P>您应该考虑交换<代码> J<代码>代码> <代码> K<代码>循环>这样的

memset(c, 0, sizeof(c[0][0])*TAM_MATRIZ*TAM_MATRIZ);
#pragma omp parallel for
for (int i=0; i < TAM_MATRIZ; i++)
for (int k=0; k < TAM_MATRIZ; k++)
for (int j=0; j < TAM_MATRIZ; j++)
  c[i][j] +=  a[i][k]*b[k][j];
memset(c,0,sizeof(c[0][0])*TAM_MATRIZ*TAM_MATRIZ);
#pragma-omp并行
对于(int i=0;i
这可能比并行化有更多的性能优势,因为它可以更好地利用缓存。但它还有一个更微妙的额外优势:它删除了求和上的依赖链

浮点数学不是关联的,这意味着(a+b)+c不一定等于a+(b+c)。当你的内循环经过
k
时,每次迭代都会写入同一个变量
c[i][j]
。如果你改变求和的顺序(例如使用SIMD),你可能会得到不同的结果