我想了解一下OpenMP,因为我想要一个巨大的并行循环。经过一些阅读(SO,Common OMP mistakes,tutorial等),我已经采取了第一步基本工作的c/mex代码下面给出(这产生了第一个测试用例不同的结果)。从多线程读取数组时需要注意什么?
- 第一测试做总结结果值 - 功能
serial, parallel
- , - 第二从输入阵列取值并写入处理的值到一个输出阵列 - 功能
serial_a, parallel_a
。
我的问题是:
- 为什么不同初试的结果,我。即
serial
和parallel
- 的结果令人惊讶的是第二个测试成功。我关心的是,如何处理可能被多线程读取的内存(阵列位置)?在这个例子中,这应该被
a[i])/cos(a[n-i]
模拟。 - 是否有一些简单的规则如何确定申报为私人,共享和减少哪些变量?
- 在这两种情况下,
int i
都在pragma
之外,但第二个测试看起来会产生正确的结果。那么是好的还是已经将i
移到pragma omp parallel
区域,as being said here? - 任何其他暗示错误的提示?
代码
#include "mex.h"
#include <math.h>
#include <omp.h>
#include <time.h>
double serial(int x)
{
double sum=0;
int i;
for(i = 0; i<x; i++){
sum += sin(x*i)/cos(x*i+1.0);
}
return sum;
}
double parallel(int x)
{
double sum=0;
int i;
#pragma omp parallel num_threads(6) shared(sum) //default(none)
{
//printf(" I'm thread no. %d\n", omp_get_thread_num());
#pragma omp for private(i, x) reduction(+: sum)
for(i = 0; i<x; i++){
sum += sin(x*i)/cos(x*i+1.0);
}
}
return sum;
}
void serial_a(double* a, int n, double* y2)
{
int i;
for(i = 0; i<n; i++){
y2[i] = sin(a[i])/cos(a[n-i]+1.0);
}
}
void parallel_a(double* a, int n, double* y2)
{
int i;
#pragma omp parallel num_threads(6)
{
#pragma omp for private(i)
for(i = 0; i<n; i++){
y2[i] = sin(a[i])/cos(a[n-i]+1.0);
}
}
}
void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
double sum, *y1, *y2, *a, s, p;
int x, n, *d;
/* Check for proper number of arguments. */
if(nrhs!=2) {
mexErrMsgTxt("Two inputs required.");
} else if(nlhs>2) {
mexErrMsgTxt("Too many output arguments.");
}
/* Get pointer to first input */
x = (int)mxGetScalar(prhs[0]);
/* Get pointer to second input */
a = mxGetPr(prhs[1]);
d = (int*)mxGetDimensions(prhs[1]);
n = (int)d[1]; // row vector
/* Create space for output */
plhs[0] = mxCreateDoubleMatrix(2,1, mxREAL);
plhs[1] = mxCreateDoubleMatrix(n,2, mxREAL);
/* Get pointer to output array */
y1 = mxGetPr(plhs[0]);
y2 = mxGetPr(plhs[1]);
{ /* Do the calculation */
clock_t tic = clock();
y1[0] = serial(x);
s = (double) clock()-tic;
printf("serial....: %.0f ms\n", s);
mexEvalString("drawnow");
tic = clock();
y1[1] = parallel(x);
p = (double) clock()-tic;
printf("parallel..: %.0f ms\n", p);
printf("ratio.....: %.2f \n", p/s);
mexEvalString("drawnow");
tic = clock();
serial_a(a, n, y2);
s = (double) clock()-tic;
printf("serial_a..: %.0f ms\n", s);
mexEvalString("drawnow");
tic = clock();
parallel_a(a, n, &y2[n]);
p = (double) clock()-tic;
printf("parallel_a: %.0f ms\n", p);
printf("ratio.....: %.2f \n", p/s);
}
}
输出
>> mex omp1.c
>> [a, b] = omp1(1e8, 1:1e8);
serial....: 13399 ms
parallel..: 2810 ms
ratio.....: 0.21
serial_a..: 12840 ms
parallel_a: 2740 ms
ratio.....: 0.21
>> a(1) == a(2)
ans =
0
>> all(b(:,1) == b(:,2))
ans =
1
系统
MATLAB Version: 8.0.0.783 (R2012b)
Operating System: Microsoft Windows 7 Version 6.1 (Build 7601: Service Pack 1)
Microsoft Visual Studio 2005 Version 8.0.50727.867
*只要parallel for循环的每次迭代都作用于不同的数组元素,则不必担心共享和私有*好。但是如果一个数组的相同元素必须被不同的线程读取呢? OMP是否照顾这一点,例如, G。一个线程只是等待一个元素被另一个元素读取的情况?或者读取访问不是问题呢?那么情况如何,一个元素可能需要通过不同的线程来改变?这可能吗? – embert 2014-09-26 03:49:56
如果数组中的相同元素必须由不同的线程读取,则不需要担心这一点。每个线程都会将数据提取到本地缓存中。但是,如果多于一个线程将写入相同的数组元素,则不必担心。这可能会导致竞争条件。您也可以在写入不同的元素时遇到问题,但在本地关闭。这被称为虚假分享。 – 2014-09-26 07:43:09