如何避免Ruby扩展中的跨线程违规?

And*_*ack 5 c ruby multithreading ruby-c-extension

我正在编写一个C扩展,提供Ruby和异步I/O库之间的接口.在我的代码上运行测试时,我经常会遇到错误,包括(但不限于):

[BUG] cross-thread violation in rb_thread_schedule()
Run Code Online (Sandbox Code Playgroud)

异步IO意味着我的C扩展需要从多个线程(而不是主解释器线程)向ruby传递消息.在此过程中如何避免这些线程安全违规?

lla*_*ram 7

对于ruby 1.8.x,避免错误的唯一方法是显而易见的 - 只从主解释器线程调用Ruby/C API.我相信这也适用于ruby 1.9.x,但我还没有使用它,也不知道它的原生线程支持如何改变它.您需要使用生产者/消费者模式将辅助本机线程的请求传递到主解释器线程中的代码,而不是让多个本机线程直接调用API.理想情况下,这样做不会不必要地阻止其他Ruby绿色线程.如果你看一下ruby实现,ruby green thread scheduler就是一个select()循环.这表明以下整体结构:

  • 创建一个管道或其他IPC机制,提供可实现的select()文件描述符.
  • 生成本机线程并为它们提供管道的写入端.
  • 在主解释器线程中,输入一个事件循环,该循环调用rb_thread_wait_fd()管道的读取端.这将允许ruby green thread调度程序运行其他绿色线程.
  • 当您的辅助本机线程有对主线程的请求时,它们将它们排队并写入管道,唤醒运行事件循环的绿色线程.

请参阅rb_io_sysread()(实现IO#sysread)可能是ruby代码库中最简单的干净IO使用函数.