我試圖從C++運行Ruby代碼塊。我有兩個Ruby函數,一個叫Init(),一個叫Loop()。我遇到的問題是,在我從SystemStackError中獲得「堆棧級別太深」之前,我只能使用Loop()很多次。據我所知,我的Ruby代碼不是遞歸的。正如你所看到的,到目前爲止,這個Ruby代碼僅僅是一個概念驗證,並且只加載了調試風格的東西,並在面板上閃爍。下面是Ruby代碼:在循環中調用C++中的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++實現面板的是:
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);
沒有工作,直到我寫了一個(犯罪嫌疑人)執行新:
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()來獲得回溯(backtrace顯示爲空)。在線沒有任何東西似乎有加載腳本作爲字符串的祕密,所以rb_eval_string()是一個猜測。 rb_load_file()也不起作用。
爲什麼這會導致堆棧問題?我可以編輯我的Ruby腳本,添加或刪除代碼,並且在執行各種循環次數後堆棧被吹掉。我可以執行的循環次數與行數沒有明顯的關係。如果我刪除一條線,我可能會得到45個循環。如果我刪除另一個,我可能會超過2000.我做錯了什麼?在下面的響應的光線更
一些代碼 - 這是給C++方法來Ruby的API調用(其中預計C風格的功能):
typedef VALUE (RubyMethod)(...);
extern "C" /*static*/ VALUE StaticRubyNew(VALUE self)
{
return MainWidget::M_this->RubyNew(self);
}
嗯,我有點接近 - 我把所有這一切都推出了純C驅動的應用程序,它至少運行500,000循環(在我殺死它之前)。這肯定是我在做一個C++到C接口的錯誤。 – Scott 2010-11-03 22:00:05