Randy Lai
Randy Lai

Reputation: 3184

Segfault when using doParallel with Rcpp module

I am trying to use Rcpp module with doParallel. However, it seems that they are not compatible. This is a example would produce segfault. I have tried similar thing with the R built-in reference class and it works fine.

require(doParallel)
require(Rcpp)
require(inline)

inc = '
using namespace Rcpp; class Uniform { public:
    Uniform(double min_, double max_) : min(min_), max(max_) {}
    NumericVector draw(int n) const {
        RNGScope scope;
        return runif( n, min, max ); }
    double min, max;
};
double uniformRange( Uniform* w) { return w->max - w->min;
}
RCPP_MODULE(unif_module) {
    class_<Uniform>( "Uniform" )
    .constructor<double,double>()
    .field( "min", &Uniform::min )
    .field( "max", &Uniform::max )
    .method( "draw", &Uniform::draw )
    .method( "range", &uniformRange )
    ;
}
'
fx <- cxxfunction(signature(), plugin="Rcpp", include=inc)
unif_module <- Module("unif_module", getDynLib(fx))
Uniform <- unif_module$Uniform

registerDoParallel(2)

myObjs = foreach(i=1:2) %dopar% {
    u <- new( Uniform, 0, 10 )
    u$draw( 10L )
    u
}
myObjs

Followed by the comment of Dirk, I tried to use Package with doParallel, but I still get segfault.

library(Rcpp)
require(doParallel)
Rcpp.package.skeleton( "MyPackage", module = TRUE )
install.packages("MyPackage", repos=NULL)
library(MyPackage)
NumEx = Module("NumEx", PACKAGE="MyPackage")
Num = NumEx$Num

registerDoParallel(2)
foreach(i=1:2) %dopar% {
    obj = new(Num)
    obj
}

FYI, the ordinary Reference class works flewlessly with doParallel.

require(doParallel)

myClass = setRefClass("myClass",
    fields = c("a"),
    methods = list(
        show = function(){cat("hello\n")}
    )
)

registerDoParallel(2)
objs = foreach(i=1:2) %dopar% {
    obj = new("myClass")
    obj$a=i
    obj
}
objs[[1]]$a

Upvotes: 0

Views: 627

Answers (1)

Dirk is no longer here
Dirk is no longer here

Reputation: 368261

There is no such thing as a 'Rcpp reference class'.

You are compiling a local extension via inline, and then shipping that (with its memory location) to the workers. That can't work and is known not to work -- they will access some random memory content.

For parallel work in this fashion, you need to build the extension by each worker --- which is why the general recommendation always is to use a package, and have each worker load the package.

Upvotes: 3

Related Questions