我試圖調用GSL庫的Monte Carlo集成子例程來進行一些數值計算。因爲我的for循環非常簡單,意味着不同運行的結果是獨立的,所以我期望使用OpenMP進行並行化應該非常簡單。但是,當我編譯它時,它總是說「內部編譯器錯誤:分段錯誤」,並且什麼都沒產生。這裏是我的代碼:OpenMP並行區域中嵌套函數的內部編譯器錯誤
#include <stdlib.h>
#include <omp.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_monte.h>
#include <gsl/gsl_monte_vegas.h>
#include <math.h>
double
Reg1 (double *x, double t, size_t dim, void *params)
{
return sin(x[1])*cos(t*t)*x[0]*x[0]*cos(x[0])*cos(3*x[0]);
}
void
display_results (char *title, double result, double error)
{
printf ("%s ==================\n", title);
printf ("result = % .10f\n", result);
printf ("sigma = % .10f\n\n", error);
}
void
VEGAS_integration_routine (double (*function)(double *, size_t, void *),
double xl[], double xu[], size_t calls, gsl_rng * r)
{
double res, err;
gsl_monte_function Function = { function, 2, 0 };
gsl_monte_vegas_state *s = gsl_monte_vegas_alloc (2);
gsl_monte_vegas_integrate (&Function, xl, xu, 2, 20000, r, s, &res, &err);
display_results ("vegas warm-up", res, err);
printf ("converging...\n");
do
{
gsl_monte_vegas_integrate (&Function, xl, xu, 2, calls, r, s, &res, &err);
printf ("result = % .10f; sigma = % .10f; "
"chisq/dof = %.2f\n", res, err, gsl_monte_vegas_chisq (s));
}
while (fabs (gsl_monte_vegas_chisq (s) - 1.0) > 0.05);
display_results ("vegas final", res, err);
gsl_monte_vegas_free (s);
}
int
main (void)
{
int seg = 200;
double xl[2] = { 195.0, -1000.0 };
double xu[2] = { 205.0, 1000.0 };
const gsl_rng_type *T;
gsl_rng *r;
size_t calls = 1000000;
gsl_rng_env_setup();
T = gsl_rng_default;
r = gsl_rng_alloc (T);
/* Calculate G1 */
int i;
double j=0;
#pragma omp parallel for shared(xl,xu,calls,r,seg) private(i,j)
for(i=0; i<=seg; i=i+1)
{
j=(double)i * 0.05;
printf("Now it's t = %.2f \n", j);
printf("Compute Re(G1)...\n");
double g(double * x, size_t dim, void *params)
{
return Reg1(x, j, dim, ¶ms);
}
VEGAS_integration_routine (&g, xl, xu, calls, r);
}
gsl_rng_free (r);
return 0;
}
此代碼基本上是從示例代碼修改於GSL webpage。不使用OpenMP,它可以很好地工作。但是,當我用gcc編譯使用以下命令(帶-fopenmp
增加),而我們的服務器上工作,
gcc -c -Wall -ansi -I/usr/include -L/usr/lib/gcc/x86_64-redhat-linux/4.4.4/ -lgomp -fopenmp test2.c -o test2.o
gcc -L/usr/lib64/ test2.o -L/usr/lib/gcc/x86_64-redhat-linux/4.4.4/ -lgomp -fopenmp -lgsl -lgslcblas -lm -o test2.out
,我得到了以下錯誤消息:
test2.c: In function 'main':
test2.c:85: internal compiler error: Segmentation fault
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://bugzilla.redhat.com/bugzilla> for instructions.
Preprocessed source stored into /tmp/ccAGFe3v.out file, please attach this to your bugreport.
make: *** [test2.o] Error 1
因爲我無法編譯它和上面顯示的錯誤信息是如此有限,我真的想知道什麼是錯誤的,所以我分解我調用的子程序VEGAS_integration_routine
,然後逐行運行它。我發現編輯停在第二行
gsl_monte_function Function = { function, 2, 0 };
這讓我很困惑。在使用OpenMP壓扁循環時,我無法在循環中聲明GSL函數嗎? GSL和OpenMP之間是否存在內部衝突?我曾在Stack Overflow和Google上搜索過,但似乎沒有相關的文章存在(太奇怪了!)。如果有人能夠解釋這裏發生了什麼,或者指出另一種做並行計算的方法,我將非常感激。我敢肯定,我寫循環的方式並不是最好的,最好的...
哇非常感謝@Hristo!我沒有意識到嵌套函數在C中是非標準的......我曾經使用支持嵌套函數來進行計算的Mathematica。無論如何,至少我學到了一些東西! 但是,在這種情況下,因爲我要通過被積函數的參考'Reg1'到GSL積分子程序(即,使用'Reg1'聲明一個'gsl_monte_function'對象,然後將其傳遞到'gsl_monte_vegas_integrate')和I '我想計算它在不同的't'值(這就是爲什麼我需要一個for循環),是否有可能不使用嵌套函數重寫它? –
這是可能的,GSL提供了特定的界面來做到這一點。我已經相應地更新了我的答案。 –
沒有比看到代碼正確工作更令人興奮的了!我非常感謝您的詳細解答! (老實說,我不明白爲什麼有一個void params指針(例如,見[這裏](http://www.gnu.org/software/gsl/manual/html_node/Monte-Carlo-Interface.html )),直到我讀你的修改後的代碼...) –