【发布时间】:2010-11-05 06:37:27
【问题描述】:
我正在尝试从 C++ 运行 Ruby 代码块。我有两个 Ruby 函数,一个叫做 Init(),一个叫做 Loop()。我遇到的问题是,在从 SystemStackError 获得“堆栈级别太深”之前,我只能 Loop() 这么多次。据我所知,我的 Ruby 代码不是递归的。如您所见,到目前为止,这段 Ruby 代码仅用于概念验证,只加载了调试风格的内容并在面板上闪烁。这是 Ruby 代码:
def Init()
puts 'Hello from script\'s Init()!'
$i = 0
$p = Panel.new
$p.Debug
$p.Extinguish( "Running" )
$p.Illuminate( "Fault" )
end
def Loop()
puts 'Hello from Loop!' + $i.to_s
$i += 1
puts $p
$p.Debug
$p.Illuminate( "Running" ) if $i % 2 == 1
$p.Extinguish( "Running" ) if $i % 2 != 1
end
我在 C++ 中的 Panel 实现是:
ruby_init();
VALUE cPanel;
cPanel = rb_define_class( "Panel", rb_cObject );
rb_define_singleton_method( cPanel, "new", (RubyMethod*)&StaticRubyNew, 0 );
rb_define_method( cPanel, "Debug", (RubyMethod*)&StaticRubyDebug, 0 );
rb_define_method( cPanel, "Extinguish", (RubyMethod*)&StaticRubyExtinguish, 1 );
rb_define_method( cPanel, "Illuminate", (RubyMethod*)&StaticRubyIlluminate, 1 );
我调用脚本函数如下:
rb_eval_string( program );
rb_funcall( Qnil, rb_intern( "Init" ), 0, NULL );
// In a 200ms loop:
rb_funcall( Qnil, rb_intern( "Loop" ), 0, NULL );
在我编写了 new 的(可疑)实现之前,没有任何效果:
VALUE MainWidget::RubyNew( VALUE clas )
{
// Looks like we have to return *something* instead of Qnil, even if I
// don't have anything to wrap yet.
const char* s = "Dude";
VALUE tdata = Data_Wrap_Struct( clas, StaticRubyMark, StaticRubyFree, const_cast<char*>(s) );
return tdata;
}
RubyMark 和 RubyFree 不做任何事情,而 RubyDebug、RubyIlluminate 等对于手头的问题也没有做任何值得注意的事情。
我尝试将 Init 和 Loop 作为类方法包装在一个类中,这样我就可以使用真正的接收器调用 rb_funcall()。我尝试通过调用 rb_protect() 来获取回溯(回溯显示为空)。网上似乎没有将脚本加载为字符串的秘密,所以 rb_eval_string() 是一个猜测。 rb_load_file() 也不起作用。
为什么这会导致堆栈问题?我可以编辑我的 Ruby 脚本,添加或删除代码,并且在执行不同数量的循环后堆栈会爆炸。我可以执行的循环数与行数没有明显的关系。如果我删除一行,我可能会得到 45 个循环。如果我删除另一个,我可能会得到超过 2000。我做错了什么?
根据下面的响应添加一些代码——这是为 Ruby API 调用(需要 C 风格的函数)提供 C++ 方法:
typedef VALUE (RubyMethod)(...);
extern "C" /*static*/ VALUE StaticRubyNew( VALUE self )
{
return MainWidget::M_this->RubyNew( self );
}
【问题讨论】:
-
好吧,我更接近一点——我将所有这些都提取到了一个纯 C 驱动的应用程序中,它运行了至少 500,000 次循环(在我杀死它之前)。这一定是我在使用 C++ 到 C 接口时做错了什么。