从ruby c扩展中的线程调用IO操作将导致ruby挂起

从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_

我在使用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代码作为回调,一旦线程接收到信号,就会执行回调

一般来说,如果回调类似于以下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);