OpenMP具体的使用方法及其注意事项。
首先声明本文主要是参考下面的网址内容进行的总结。详细信息可以参考下面的网址。
http://software.intel.com/zh-cn/articles/intel-guide-for-developing-multithreaded-applications/
- void processQuadArray (int imx, int jmx, int kmx,
- double**** w, double**** ws)
- {
- for (int nv = 0; nv < 5; nv++)
- for (int k = 0; k < kmx; k++)
- for (int j = 0; j < jmx; j++)
- for (int i = 0; i < imx; i++)
- ws[nv][k][j][i] = Process(w[nv][k][j][i]);
- }
如果线程数量多余或少于五个,并行外部循环将会导致负载不平衡和闲置线程。如果阵列维数imx、jmx和kmx非常大的话,并行效率将会很低。这种情况下最好选择并行其中一个内部循环。
如果能确保安全性,应尽可能排除工作分享结构底端的隐性障碍。所有 OpenMP 工作分享结构(不论整段还是单个)均在结构块底端含有一个隐性障碍。只有所有线程都在此障碍处集合后,并行才能执行。有时,这些障碍很不必要,并且会影响性能。应使用 OpenMP nowait 子句来消除这些障碍,如下面这个示例:
- void processQuadArray (int imx, int jmx, int kmx,
- double**** w, double**** ws)
- {
- #pragma omp parallel shared(w, ws)
- {
- int nv, k, j, i;
- for (nv = 0; nv < 5; nv++)
- for (k = 0; k < kmx; k++) // kmx is usually small
- #pragma omp for shared(nv, k) nowait
- for (j = 0; j < jmx; j++)
- for (i = 0; i < imx; i++)
- ws[nv][k][j][i] = Process(w[nv][k][j][i]);
- }
- }
由于最内层循环的计算都是独立的,因此在进行下一次迭代之前,线程没有必要在隐性障碍处等待。如果每次迭代的工作量各不相同,nowaitnowait 子句可使线程继续处理有用工作,而非闲置在隐性障碍处。
如果一个循环带有一种可防止循环被并行执行的循环传递相关性,可以将循环体分裂成单独的循环,进而实现并行执行。一个循环体被划分为两个或两个以上的循环被称为“循环分裂”。下面的示例演示了循环分裂过程,一个具有循环传递相关性的循环体创建出新的循环,进而完成并行执行。
- float *a, *b;
- int i;
- for (i = 1; i < N; i++) {
- if (b[i] > 0.0)
- a[i] = 2.0 * b[i];
- else
- a[i] = 2.0 * fabs(b[i]);
- b[i] = a[i-1];
- }
但是,若将一个循环体分裂成两个独立的操作,这两个操作均可并行执行,如下面的代码:
- for (i = 1; i < N; i++)
- {
- if (b[i] > 0.0)
- a[i] = 2.0 * b[i];
- else
- a[i] = 2.0 * fabs(b[i]);
- }
- for(i = 1; i<N; i++)
- b[i] = a[i-1];