【问题标题】:How do I avoid cross-thread violations in a Ruby extension?如何避免 Ruby 扩展中的跨线程冲突?
【发布时间】:2010-09-20 13:39:58
【问题描述】:
我正在编写一个 C 扩展,提供 Ruby 和异步 I/O 库之间的接口。在我的代码上运行测试时,我经常遇到错误,包括(但不限于):
[BUG] cross-thread violation in rb_thread_schedule()
异步 IO 意味着我的 C 扩展需要从多个线程(而不是主解释器线程)向 ruby 传递消息。在此过程中如何避免这些违反线程安全的行为?
【问题讨论】:
标签:
c
ruby
multithreading
ruby-c-extension
【解决方案1】:
对于 ruby 1.8.x,避免错误的唯一方法是显而易见的——只从主解释器线程调用 Ruby/C API。我相信这也适用于 ruby 1.9.x,但我没有使用过它,也不知道它的原生线程支持会如何改变事情。您需要使用生产者/消费者模式将来自辅助本机线程的请求传递到主解释器线程中的代码,而不是让多个本机线程直接调用 API。理想情况下,这样做同时不会不必要地阻塞其他 Ruby 绿色线程。如果您查看 ruby 实现,那么 ruby green 线程调度程序本质上是一个select() 循环。这表明了以下总体结构:
- 创建提供真正
select()-able 文件描述符的管道或其他IPC 机制。
- 生成本机线程并为它们提供管道的写入端。
- 在主解释器线程中,进入一个事件循环,该循环在管道的读取端调用
rb_thread_wait_fd()。这将允许 ruby 绿色线程调度程序运行其他绿色线程。
- 当您的辅助本机线程有对主线程的请求时,它们会将它们排队并写入管道,从而唤醒运行您的事件循环的绿色线程。
请参阅rb_io_sysread()(IO#sysread 的实现)了解可能是 ruby 代码库中最简单的干净 IO 使用函数。