C++ OpenMP在SEIR模型的Rcpp代码中生成SEGFULT

C++ OpenMP在SEIR模型的Rcpp代码中生成SEGFULT,c++,r,openmp,rcpp,armadillo,C++,R,Openmp,Rcpp,Armadillo,我编写了一个(可能效率很低,但无论如何…)Rcpp代码,使用内联来模拟随机过程。 串行版本的编译和工作非常完美,但因为我需要从中进行大量模拟,而且在我看来,这似乎是一个令人尴尬的并行问题(只需要再次模拟其他参数值,并返回一个带有结果的矩阵)我试图为添加#pragma omp parallel,并使用-fopenmp-lgomp进行编译,但。。。繁荣 即使是很小的例子,我也会得到一个segfault! 我尝试添加setenv(“OMP_STACKSIZE”,“24M”,1)和值远远超过24M,但仍

我编写了一个(可能效率很低,但无论如何…)Rcpp代码,使用内联来模拟随机过程。 串行版本的编译和工作非常完美,但因为我需要从中进行大量模拟,而且在我看来,这似乎是一个令人尴尬的并行问题(只需要再次模拟其他参数值,并返回一个带有结果的矩阵)我试图为添加
#pragma omp parallel,并使用
-fopenmp-lgomp
进行编译,但。。。繁荣 即使是很小的例子,我也会得到一个segfault! 我尝试添加
setenv(“OMP_STACKSIZE”,“24M”,1)和值远远超过24M,但仍会发生segfault

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

竞态条件可能发生的唯一原因是,如果代码试图并行执行内部循环中的一组指令(由于模型结构,这无法完成,在迭代
t
时,它取决于迭代
t-1
),而不是并行外部循环,但是如果我没有弄错的话,这就是
并行for
构造函数在默认情况下所做的,如果放在外部的话

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

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);
谢谢你的帮助


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

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

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

。。。
#pragma omp临界值(随机)
rN(k)=((pp<1。)?(rbinom(1,(双)n,pp))(0):n;
...
如果((费率(0)+费率(6))>0){
#pragma omp临界值(随机)
nX=rbinom(1,S_prev,1-exp(-(比率(0)+比率(6))*tau))(0);
...
请注意,
critical
构造在它后面的结构化块上运行,因此会锁定整个语句

#pragma omp critical(random)
x = slow_computation(rbinom(...));
这最好转化为:

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

这样,只有rb=rbinom(…);
语句将受到保护。

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

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

。。。
#pragma omp临界值(随机)
rN(k)=((pp<1。)?(rbinom(1,(双)n,pp))(0):n;
...
如果((费率(0)+费率(6))>0){
#pragma omp临界值(随机)
nX=rbinom(1,S_prev,1-exp(-(比率(0)+比率(6))*tau))(0);
...
请注意,
critical
构造在它后面的结构化块上运行,因此会锁定整个语句

#pragma omp critical(random)
x = slow_computation(rbinom(...));
这最好转化为:

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

这样,只有rb=rbinom(…);
语句将受到保护。

尝试在<2分钟内将问题减少到可复制/可读的程度。我看到对函数的调用,如
rbinom
rmultiminal
;请参阅,以了解为什么这无法按预期工作的详细信息。如果从OpenMP部分调用R,如果代码爆炸,请不要感到惊讶。R是不是多线程的或可重入的。@KevinUshey,
rbinom
rmultimonomial
在串行版本中工作,而在并行版本中,我没有机会看到它们的行为是否异常。@DirkEddelbuettel这不是我的代码所做的。在计算结果(并行)后,主线程应返回R a矩阵。请注意,
OMP\U STACKSIZE
仅控制附加OpenMP线程的堆栈大小。它不会影响主线程的堆栈大小。如果怀疑堆栈存在问题,并且在类Unix操作系统上运行,则可能应使用
ulimit-s…
。请尝试减少pro在<2分钟内可复制/可读的问题。我看到对函数的调用,如
rbinom
rmultinomal
;请参阅,以了解为什么这不能像您预期的那样工作。如果您从OpenMP部分调用R,如果您的代码爆炸,请不要感到惊讶。R不是多线程的或可重入的。@KevinUshey,
rbinom
r多项式
在串行版本中工作,而在并行版本中,我没有机会看到它们的行为是否异常。@DirkEddelbuettel这不是我的代码所做的。在计算结果(并行)后,主线程应返回R a矩阵。请注意,
OMP_STACKSIZE
仅控制附加OpenMP线程的堆栈大小。它不会影响主线程的堆栈大小。如果您怀疑堆栈存在问题,并且在类Unix操作系统上运行,则可能应该使用
ulimit-s…
。再次感谢,我只想我想向未来的观众指出,尽管这个解决方案最终成功了,但我还是选择了boost::random并遵循了这一点