从ruby c扩展中的线程调用IO操作将导致ruby挂起
我在使用C扩展中的线程异步运行ruby代码时遇到问题 我有以下C代码:从ruby c扩展中的线程调用IO操作将导致ruby挂起,c,ruby,multithreading,ruby-c-extension,C,Ruby,Multithreading,Ruby C Extension,我在使用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_
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代码作为回调,一旦线程接收到信号,就会执行回调
一般来说,如果回调类似于以下ruby代码,那么这种方法可以正常工作:
1 + 1
但是,如果回调ruby代码如下所示:
puts "test"
一旦执行回调,主ruby进程将停止响应。
线程仍在运行,并且能够对信号做出反应,并在每次线程收到消息时进行“测试”
谁能告诉我,怎么解决这个问题
非常感谢:
从Ruby 1.9开始,Ruby支持一个内核的本地1:1线程
每个Ruby线程对象的线程数。目前,有一个GVL(全局虚拟机)
锁),防止Ruby代码同时执行
由rb_线程_调用_发布,无需gvl和
rb_线程_调用_而不调用_gvl2函数。这些功能是
在thread.c中使用和记录的技巧;之前不要使用它们
阅读thread.c中的注释
TLDR;Ruby VM目前(在编写本文时)不是线程安全的。查看以更好地全面了解如何在这些范围内工作
您可以使用Ruby,它将在幕后使用pthread\u create
。您可以在方法定义上方的文档中了解一些缺点。然后可以使用Ruby的方法运行回调。另外,我还没有在这里做过,但是创建一个包装器方法可能是一个好主意,这样您就可以使用rb\u protect
来处理回调可能引发的异常(否则它们将被VM吞噬)
我认为这是不被支持的,MRI有理由有GIL:我想它至少与GC有关。你可以试着问一下Ruby邮件列表,在我看来这是一个更合适的地方。嘿,就我所理解的GIL而言,每次只有一个线程能够执行IO。这对我来说太好了。但不知何故,在我线程中的IO完成后,主程序无法继续工作。如果主进程暂时停止工作,则另一个线程正在进行IO,但之后,它应该继续工作。因此,在线程中执行ruby代码之后,也许我必须发布GIL?您试图做的事情很有趣,但这与我对ruby内部的理解相去甚远,我不认为您会找到一位如此精通ruby的人来回答您的问题;我建议您试穿一下“让我知道”如果您这样做,我希望跟进讨论;)
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);