我使用嵌入式Ruby(Ruby版本1.8.6)从CPP调用ruby代码。我将Ruby代码传递给rb_eval_string(),这将创建一个新线程。多次运行此cpp代码(大约20)导致带有SIGSEGV的核心转储(信号11),堆栈跟踪显示核心是由于eval.c的rb_eval_string()中引发异常引起的:
#5 <signal handler called>
#6 rb_longjmp (tag=6, mesg=365482760) at eval.c:4634
#7 0x00002aaaabd7fdc1 in rb_exc_raise (mesg=6) at eval.c:4650
#8 0x00002aaaabd89ae2 in eval (self=365613880, src=367575400, scope=4, file=0x15ad1f99 "(eval)", line=140)
at eval.c:6565
#9 0x00002aaaabd8a631 in rb_eval_string (str=0x2aaaac0bffe0 "<String containing ruby code which is passed to this function>"...)
at eval.c:1707
要在我的CPP代码中处理此异常,我使用rb_eval_string_protect()而不是rb_eval_string()并尝试打印rb_eval_string_protect()返回的状态。通过此更改,SIGABRT(信号6)仍然会发生崩溃,并且使用VALUE对象(状态)在我的CPP代码中显示以下execption消息,该对象由rb_eval_string_protect()填充:
Exception thrown is: (eval):223:in `initialize': can't start a new thread (frozen ThreadGroup)
上述例外的原因是什么?应该怎么做才能避免呢?
以下是我传递给rb_eval_string_protect()的ruby代码:
"require 'monitor'\n"
"require 'socket'\n"
"include RubyInterpreter\n"
"$rubyPort = 11111;\n"
"$isEmbeddedLoopReady = false;\n"
"$hasEmbeddedLoopFinished = false;\n"
"def newServer()\n"
"while true\n"
"begin\n"
"server = TCPServer.new(\"localhost\", $rubyPort);\n"
"break;\n"
"rescue;\n"
"$rubyPort += 1;\n"
"end\n"
"end\n"
"return server\n"
"end\n"
"$rubyMonitor = Monitor.new\n"
"class MultiMap\n"
"def initialize()\n"
"@mHashMap = Hash.new\n"
"end\n"
"def store(value)\n"
"$rubyMonitor.synchronize do\n"
"key = value.__id__\n"
"if (nil == @mHashMap[key])\n"
"@mHashMap[key] = Array.new()\n"
"end\n"
"elem = @mHashMap[key]\n"
"elem.push(value);\n"
"end\n"
"end\n"
"def delete(value)\n"
"$rubyMonitor.synchronize do\n"
"key = value.__id__\n"
"if (@mHashMap[key] != nil)\n"
"elem = @mHashMap[key].pop();\n"
"if(@mHashMap[key].length == 0)\n"
"@mHashMap.delete(key)\n"
"end\n"
"return elem;\n"
"end\n"
"end\n"
"return nil\n"
"end\n"
"end\n"
"class MyThread < Thread\n"
" def initialize(firstTask)\n"
" super()\n"
" @owner = firstTask\n"
" end\n"
" def getOwner()\n"
" return @owner\n"
" end\n"
"end\n"
"def embeddedLoop()\n"
" keepRunning = false;\n"
" server = newServer();\n"
" $isEmbeddedLoopReady = true;\n"
" if (session = server.accept) then\n"
" keepRunning = true;\n"
" end;\n"
" $runningTaskCount = 0\n"
" while(keepRunning == true)\n"
" session.read(1);\n"
" rubyTask = RubyInterpreter.getRubyTask()\n"
" if(rubyTask != nil)\n"
" $runningTaskCount += 1\n"
" s = MyThread.new(rubyTask){\n"
" begin \n"
" rubyTask.execute()\n"
" $runningTaskCount -= 1\n"
" rescue StandardError\n"
" rubyTask.notifyCompletion()\n"
" $runningTaskCount -= 1\n"
" end\n"
" }\n"
" else\n"
" keepRunning = false\n"
" end\n"
" end\n"
" $hasEmbeddedLoopFinished = true\n"
"end\n"
"$embeddedLoopThread = Thread.new {\n"
" begin \n"
" embeddedLoop()\n"
" rescue StandardError\n"
" puts \"**** CRITICAL INTERNAL ERROR ****\"\n"
" puts $!.backtrace.join(\"\\n\") \n"
" end \n"
" }\n"
" while($isEmbeddedLoopReady == false)\n"
" end \n";
因为我从Ruby代码调用了一个cpp方法RubyInterpreter.getRubyTask(),所以我定义了以下内容: sModule = rb_define_module(“RubyInterpreter”); rb_gc_register_address(安培; sModule); rb_define_singleton_method(sModule,“getRubyTask”,reinterpret_cast(RubyInterpreter :: getRubyTask),0);
RubyInterpreter.getRubyTask()返回一个简单的Ruby任务,例如puts'Hello!'
似乎从eval.c的rb_thread_start_0()抛出异常。
谢谢, 阿尔蒂