OpenMP在SEIR模型的Rcpp代码中生成段错误

时间:2013-10-16 21:39:44

标签: c++ r openmp rcpp armadillo

我写了一个(可能是低效的,但无论如何......)Rcpp代码,使用内联来模拟随机SEIR model。 串行版本编译和工作完美,但因为我需要从它模拟很多次,因为在我看来,这似乎是一个令人尴尬的并行问题(只需要再次模拟其他参数值并返回带结果的矩阵)我尝试添加#pragma omp parallel for并使用-fopenmp -lgomp进行编译但是......繁荣! 即使是非常小的例子,我也会遇到段错误! 我尝试添加setenv("OMP_STACKSIZE","24M",1);和超过24M的值,但仍然发生了段错误。

我将简要解释代码,因为它有点长(我试图缩短它但结果改变了,我无法重现它......): 我有两个嵌套循环,内部循环执行给定参数集的模型,外部循环更改参数。

竞争条件可能发生的唯一原因是代码是否试图并行执行 inner 循环内部的指令集(由于模型结构无法完成,在迭代{{ 1}}它取决于迭代t)而不是并行化外部,但是如果我没有弄错那就是t-1构造函数默认为默认情况下在外面......

这基本上是我试图运行的代码的形式:

parallel for

我的问题是:我如何告诉编译器我只想并行计算外部循环(甚至静态地为每个线程分配它们,如n_loops / n_threads)而不是内部循环(实际上是不可并行化的) ?

真正的代码涉及更多,如果你真的愿意,我会在这里为了重现性而提供它,但我只是询问OpenMP的行为。请注意,唯一的OpenMP指令显示在第mat result(n_param,T_MAX); #pragma omp parallel for for(int i=0,i<n_param_set;i++){ t=0; rowvec jnk(T_MAX); while(t < T_MAX){ ... jnk(t) = something(jnk(t-1)); ... t++; } result.row(i)=jnk; } return wrap(result); 行。

122

感谢您的帮助!

注意:在你问之前,我稍微修改了Rcpp多项式采样函数,因为我喜欢这种方式而不是使用指针...不是任何其他特殊原因! :)

1 个答案:

答案 0 :(得分:1)

R中的核心伪随机数生成器(PRNG)并非设计用于多线程环境。也就是说,它们的状态存储在静态数组(dummy中的src/main/PRNG.c)中,因此在所有线程之间共享。此外,还使用了其他几种静态结构来存储核心PRNG的更高级接口的状态。

一种可能的解决方案可能是您将每个调用rnorm()或其他采样函数放在命名的关键部分中,所有这些函数都具有相同的名称,例如:

...
#pragma omp critical(random)
rN(k) = ((pp < 1.) ? (rbinom(1,(double) n,  pp))(0) : n);
...
if((rates(0)+rates(6))>0){
   #pragma omp critical(random)
   nX = rbinom(1,S_prev,1-exp(-(rates(0)+rates(6))*tau))(0);
...

请注意,critical构造对其后面的结构化块进行操作,因此会锁定整个语句。如果在对耗时函数的调用中内联绘制随机数,例如

#pragma omp critical(random)
x = slow_computation(rbinom(...));

这更好地转变为:

#pragma omp critical(random)
rb = rbinom(...);
x = slow_computation(rb);

这样只会保护rb = rbinom(...);语句。