Dav*_*vid 0 c++ r calling-convention rcpp
我正在开发一个带有 C++ 函数的 R 包。我使用 Rcpp。编写和测试时一切正常。但是,当我完成并循环运行它时,我偶尔会收到以下警告和错误:

警告:“.Call”中的堆栈不平衡,78 然后是 77
警告:'{' 中的堆栈不平衡,75 然后是 74
警告:“.Call”中的堆栈不平衡,78 然后是 79
警告:'{' 中的堆栈不平衡,75 然后是 76
警告:“.Call”中的堆栈不平衡,78 然后是 77
警告:'{' 中的堆栈不平衡,75 然后是 74
所以我用谷歌搜索堆栈不平衡,我发现:
本文指出堆栈不平衡通常是由语言之间调用约定的差异(不匹配)引起的。据我所知,callng约定是调用者函数删除局部变量还是被调用者函数删除的约定。
我发现了这个:
http://www.stats.uwo.ca/faculty/murdoch/software/compilingDLLs/
它说 R 正在使用cdecl而 C++ 使用stdcall.
“如果您的函数使用了
stdcall而不是cdecl,则返回时可能会发生崩溃,因为您的参数将在它们已经消失后从堆栈中删除。”
如果我在声明中犯了任何错误,请告诉我。
这是我的 R 代码调用的 C++ 函数:
//[[Rcpp::export]]
int compute(SEXP p_in, Rcpp::NumericVector a) {
Rcpp::XPtr<emcdf> p(p_in);
p->cdf(a);
return p->getResult();
}
//p_in is an external pointer(pointer to an emcdf object in C++)
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是,我该如何解决这个问题?
我感谢您的帮助。
谢谢各位的回答。这是更多代码:
//declaration of class "emcdf"
class emcdf{
public:
explicit emcdf(Rcpp::NumericMatrix& x, int n);
~emcdf();
void cdf(Rcpp::NumericVector& a);
int getResult();
private:
int num;
int k;
std::thread* t;
std::vector<Rcpp::NumericMatrix*> data;
int size;
int* result;
void (*ptr) (Rcpp::NumericMatrix*, Rcpp::NumericVector, int*);
void find_func();
};
//definition of class "emcdf"
emcdf::emcdf(Rcpp::NumericMatrix& x, int n){
//initialize members
t = new std::thread[n];
num = n;
k = x.ncol();
size = x.nrow()/num;
result = new int[num];
find_func();
int i = 0;
for(; i<num - 1; ++i)
data.push_back(copy(x, i*size, size));
data.push_back(copy(x, i*size, x.nrow() - i*size));
}
emcdf::~emcdf(){
delete[] t;
for(int i=0; i<num; ++i)
delete data[i];
delete[] result;
}
void emcdf::cdf(Rcpp::NumericVector& a){
for(int i=0; i<num; ++i){
t[i] = std::thread(*ptr, data[i], a, result + i);
}
for(int i=0; i<num; ++i)
t[i].join();
}
int emcdf::getResult(){
int sum = 0;
for(int i=0; i<num; ++i)
sum += result[i];
return sum;
}
//other functions
Rcpp::NumericMatrix* copy(Rcpp::NumericMatrix& x, int row, int nrow){
NumericMatrix* out = new NumericMatrix(nrow, x.ncol());
int firstRow = 0;
while(firstRow < nrow){
for(int j=0; j<x.ncol(); ++j){
out->at(firstRow,j) = x.at(firstRow + row,j);
}
++firstRow;
}
return out;
}
//makes "emcdf" pointer
//[[Rcpp::export]]
RcppExport SEXP build(SEXP x_in, int num){
Rcpp::NumericMatrix x(x_in);
emcdf* em = new emcdf(x, num);
Rcpp::XPtr<emcdf> p(em, true);
return p;
}
//take pointer of "emcdf" from build() and compute cdf results
//[[Rcpp::export]]
int compute(SEXP& p_in, Rcpp::NumericVector& a){
Rcpp::XPtr<emcdf> p(p_in);
p->cdf(a);
return p->getResult();
}
Run Code Online (Sandbox Code Playgroud)
compute() 中的参数 SEXP& p_in 是从 build() 的返回值传递过来的。在我的 R 代码中,我调用了 compute() 并得到了堆栈不平衡错误。它不会每次都出现,但是当连续调用超过 1000 次时,很可能会出错。
Kevin Ushey 建议:
“看起来这里的问题只是您试图在单独的线程中使用 R/Rcpp,但不幸的是这不起作用(因为您最终可能会从单独的线程触发垃圾收集器) .”
这是否意味着如果我避免在单独的线程中使用 Rcpp 函数/对象,例如,不使用*ptr我的线程运行的NumericMatrix ,这个错误将被修复?
谢谢你。
不幸的是,我认为您的初步诊断走错了路。
当 R 报告堆栈不平衡时,这意味着内部保护堆栈(用于保护堆栈上的 R 对象免受垃圾收集器的影响)不平衡,表明某些 C/C++ 例程在某处不同步。这与调用约定无关。
Rcpp 通常在保护堆栈之外管理其对象的保护;它明确使用R_PreserveObject()和R_ReleaseObject()API,它们不是基于堆栈的。
没有可重现的示例,很难说更多,但最可能的原因是您在尚未显示的单独代码中对PROTECT()/ 的调用不匹配UNPROTECT()。
| 归档时间: |
|
| 查看次数: |
330 次 |
| 最近记录: |