我想了解一下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