我在使用C扩展中的线程运行ruby代码异步时遇到问题。
我有以下C代码:
struct DATA {
VALUE callback;
pthread_t watchThread;
void *ptr;
};
void *executer(void *ptr) {
struct DATA *data = (struct DATA *) ptr;
char oldVal[20] = "1";
char newVal[20] = "1";
pthread_cleanup_push(&threadGarbageCollector, data);
while(1) {
if(triggerReceived) {
rb_funcall(data->callback, rb_intern("call"), 0);
}
}
pthread_cleanup_pop(1);
return NULL;
}
VALUE spawn_thread(VALUE self) {
VALUE block;
struct DATA *data;
Data_Get_Struct(self, struct DATA, data);
block = rb_block_proc();
data->callback = block;
pthread_create(&data->watchThread, NULL, &executer, data);
return self;
}
我正在使用它,因为我想提供ruby-code作为回调,一旦Thread收到信号就会执行回调。
一般情况下,如果回调类似于这个ruby-code:
,这样可以正常工作1 + 1
但是,如果回调ruby-code看起来像这样:
puts "test"
一旦回调被执行,主ruby进程将停止响应。 线程仍然在运行,能够对信号作出反应,并将" test"每次,线程都会收到一条消息。
有人可以告诉我,如何解决这个问题?
非常感谢
答案 0 :(得分:1)
从Ruby 1.9开始,Ruby支持一个内核的本机1:1线程 每个Ruby线程对象的线程数。当前,有一个GVL(全局VM 锁定)可防止同时执行可能是 由rb_thread_call_without_gvl发布,并且 rb_thread_call_without_gvl2函数。这些功能是 难以使用,并记录在thread.c中;之前不要使用它们 在thread.c中阅读评论。
TLDR; Ruby VM当前(在编写本文时)不是线程安全的。请访问this nice write-up on Ruby Threading,以更好地全面了解如何在这些范围内工作。
您可以使用Ruby的native_thread_create(rb_thread_t *th),后者将在幕后使用pthread_create
。您可以在方法定义上方的文档中了解一些缺点。然后,您可以使用Ruby的rb_thread_call_with_gvl方法运行回调。另外,我在这里还没有做过,但是创建一个包装方法可能是一个好主意,因此您可以使用rb_protect
处理回调可能引发的异常(否则它们将被VM吞噬)。 / p>
VALUE execute_callback(VALUE callback)
{
return rb_funcall(callback, rb_intern("call"), 0);
}
// execute your callback when the thread receives signal
rb_thread_call_with_gvl(execute_callback, data->callback);