在循环中从C ++调用Ruby函数会导致“堆栈级别太深”

时间:2010-11-02 23:24:02

标签: c++ ruby

我正在尝试从C ++运行Ruby代码块。我有两个Ruby函数,一个叫做Init(),另一个叫做Loop()。我遇到的问题是,在从SystemStackError获得“堆栈级太深”之前,我只能循环()多次。据我所知,我的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.我做错了什么?

根据下面的响应,还有一些代码 - 这是为了给Python API调用提供C ++方法(期望C风格的函数):

typedef VALUE (RubyMethod)(...);
extern "C" /*static*/ VALUE StaticRubyNew( VALUE self )
{
    return MainWidget::M_this->RubyNew( self );
}

1 个答案:

答案 0 :(得分:1)

好的,所以我把它减少了,直到我得到一个类似于我的C实现的工作版本,但问题与C ++ vs C无关。上面没有显示的内容(因为我认为它不相关)是这是一个Qt应用程序,我有两个插槽 - 一个用于初始化ruby并加载程序,另一个用于调用循环函数。从计时器(不相关)重复调用后一个时隙。当我将ruby_init()移出插槽并进入main()时,突破发生了。在Google上进行的搜索显示了这个有趣的answer

来自Matz本人,“没有Ruby对象应该从堆栈区域引用低于 ruby_init()调用时的位置。“

所以发生的事情是当每个槽被调用时,它们位于堆栈的不确定位置,而如果你从main()调用ruby_init()然后开始运行Qt的事件循环,你肯定会在堆栈上的正确位置是做rb_funcall()等。

相关问题